为角色管理配置应用程序 roleManager 元素

 为角色管理配置应用程序 roleManager 元素
2008年7月17日 11:17
roleManager 元素(ASP.NET 设置架构)





为角色管理配置应用程序。

此元素是 .NET Framework 2.0 版中的新元素。


configuration 元素(常规设置架构)

  system.web 元素(ASP.NET 设置架构)

    roleManager 元素(ASP.NET 设置架构)






<roleManager
cacheRolesInCookie="true|false"
cookieName="name"
cookiePath="/"
cookieProtection="All|Encryption|Validation|None"
cookieRequireSSL="true|false "
cookieSlidingExpiration="true|false "
cookieTimeout="number of minutes"
createPersistentCookie="true|false"
defaultProvider="provider name"
domain="cookie domain">
enabled="true|false"
maxCachedResults="maximum number of role names cached"
<providers>...</providers>
</roleManager>





 属性和元素



下面几部分描述了本节涉及的属性、子元素和父元素。

属性




   
       
           
           

属性

           
               
           

说明

           
       

       
           
           

cacheRolesInCookie

           
               
           

可选的 Boolean 属性。

           

指定当验证某个用户是否在特定角色中时,先检查 Cookie,然后使用角色提供程序在数据源中检查角色列表。如果为 true,则缓存当前用户的 Cookie 中的角色名称列表;否则为 false。

           

默认值为 false。

           
       

       
           
           

cookieName

           
               
           

可选的 String 属性。

           

指定存储角色名称的 Cookie 的名称。

           

默认值为 ".ASPXROLES"。

           
       

       
           
           

cookiePath

           
               
           

可选的 String 属性。

           

角色名称 Cookie 的路径。

           

默认值为 "/"。

           
       

       
           
           

cookieProtection

           
               
           

可选的 CookieProtection 属性。

           

指定 CookieProtection 枚举值之一。

           

默认值为 All 值。

           
       

       
           
           

cookieRequireSSL

           
               
           

可选的 Boolean 属性。

           

指定角色名称 Cookie 是否需要使用 SSL 来发送到服务器。

           

如果设置为 true,则角色名称 Cookie 需要使用 SSL 来发送到服务器。

           

默认值为 false。

           
       

       
           
           

cookieSlidingExpiration

           
               
           

可选的 Boolean 属性。

           

指定是否将定期重置角色名称 Cookie 的过期日期和时间。

           

如果设置为 true,则 Cookie 的过期日期和时间最初将设置为当前日期和时间与 CookieTimeout 值(分钟)的加和。当用户继续主动地使用 ASP.NET 应用程序时,Cookie 的过期日期和时间将在剩余时间不足 CookieTimeout 值的一半时自动更新。有关更多信息,请参见 Expires。

           

默认值为 true。

           
       

       
           
           

cookieTimeout

           
               
           

可选的 Int32 属性。

           

角色名称 Cookie 过期之前的时间(分钟)。

           

默认值为 "30"(分钟)。

           
       

       
           
           

createPersistentCookie

           
               
           

可选的 Boolean 属性。

           

指定角色名称 Cookie 是否为会话 Cookie;即,该 Cookie 会在浏览器关闭时丢失。

           

如果设置为 true,则角色名称 Cookie 是可跨多个浏览器会话使用的持久性 Cookie。持久性 Cookie 的过期日期和时间设置为当前的日期和时间与 CookieTimeout 值(分钟)的加和。

           

默认值为 false。

           
       

       
           
           

defaultProvider

           
               
           

可选的 String 属性。

           

默认角色提供程序的名称。有关更多信息,请参见 Provider。

           

默认值为 "AspNetSqlRoleProvider"。

           
       

       
           
           

domain

           
               
           

可选的 String 属性。

           

指定角色名称 Cookie 的 Domain 值。

           

默认值为 HttpCookie 属性默认值,该值为空字符串 ("")。

           
       

       
           
           

enabled

           
               
           

可选的 Boolean 属性。

           

指定是否要启用角色管理。

           

如果设置为 true,则启用角色管理。

           

在 Machine.config 文件中,默认值为 false。

           
       

       
           
           

maxCachedResults

           
               
           

可选的 Int32 属性。

           

指定缓存在角色 Cookie 中的角色名称的最大数目。

           

默认值为 25。

           
       

       
           
           

继承的属性

           
               
           

可选的属性。

           

由所有 section 元素继承的属性。有关更多信息,请参见节元素所继承的常规属性。

           
       

   


子元素




   
       
           
           

元素

           
               
           

说明

           
       

       
           
           

providers

           
               
           

可选的元素。

           

为角色管理定义一个角色提供程序的集合。

           
       

   


父元素




   
       
           
           

元素

           
               
           

说明

           
       

       
           
           

configuration

           
               
           

指定公共语言运行库和 .NET Framework 应用程序所使用的每个配置文件中均需要的根元素。

           
       

       
           
           

system.web

           
               
           

为 ASP.NET 配置节指定根元素。

           
       

   






 备注



roleManager 元素为角色管理配置应用程序。

有关访问和修改应用程序代码中 roleManager 元素的配置值的信息,请参见 RoleManagerSection。

默认配置


下面的默认 roleManager 元素不是在 Machine.config 文件或根 Web.config 文件中显式配置的。但是,它是应用程序返回的默认配置。提供程序在 Machine.config 文件中是显式配置的。




 复制代码


<roleManager
enabled="false"
cacheRolesInCookie="false"
cookieName=".ASPXROLES"
cookieTimeout="30"
cookiePath="/"
cookieRequireSSL="false"
cookieSlidingExpiration="true"
cookieProtection="All"
defaultProvider="AspNetSqlRoleProvider"
createPersistentCookie="false"
maxCachedResults="25">
<providers>
<clear />
<add
connectionStringName="LocalSqlServer"
applicationName="/"
name="AspNetSqlRoleProvider"
type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<add
applicationName="/"
name="AspNetWindowsTokenRoleProvider"
type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</roleManager>








 示例



下面的代码示例演示如何配置一个 ASP.NET 应用程序,以使用 SqlRoleProvider 类来存储和检索角色信息。




 复制代码


<configuration>
<system.web>
<roleManager defaultProvider="SqlProvider"
enabled="true"
cacheRolesInCookie="true"
cookieName=".ASPROLES"
cookieTimeout="30"
cookiePath="/"
cookieRequireSSL="false"
cookieSlidingExpiration="true"
cookieProtection="All" >
<providers>
<add
name="SqlProvider"
type="System.Web.Security.SqlRoleProvider"
connectionStringName="SqlServices"
applicationName="SampleApplication" />
</providers>
</roleManager>
</system.web>
</configuration>







 元素信息






   
       
           
           

配置节处理程序

           
               
           

RoleManagerSection

           
       

       
           
           

配置成员

           
               
           

RoleManager

           
       

       
           
           

可配置的位置

           
               
           

Machine.config

           

根级别的 Web.config

           

应用程序级别的 Web.config

           
       

       
           
           

要求

           
               
           

Microsoft Internet 信息服务 (IIS) 版本 5.0、5.1 或 6.0

           

.NET Framework 2.0 版

           

Microsoft Visual Studio 2003 或 Visual Studio 2005

           
       

   









[新闻]微软4.86亿美元收购Greenfield
ASP.NET SQL Server 注册工具 (Aspnet_regsql.exe)
2008年7月12日 22:13
.NET Framework 工具
ASP.NET SQL Server 注册工具 (Aspnet_regsql.exe)



 

ASP.NET SQL Server 注册工具用于创建供 ASP.NET 中的 SQL Server 提供程序使用的 Microsoft SQL Server 数据库,或者用于在现有数据库中添加或移除选项。Aspnet_regsql.exe 文件位于 Web 服务器上的 [drive:]/WINDOWS/Microsoft.NET/Framework/versionNumber 文件夹中。

可以不带任何命令行参数运行 Aspnet_regsql.exe,以运行一个引导您完成如下过程的向导:为 SQL Server 安装指定连接信息,并为成员资格、角色管理器、配置文件、Web 部件个性化设置及运行状况监视等功能安装或移除数据库元素。(该向导不涉及设置会话状态和 SQL 缓存依赖项。)使用下表所列的选项,还可以将 Aspnet_regsql.exe 作为命令行工具来运行,以便为各个功能指定要添加或移除的数据库元素。

语法





 复制代码


Aspnet_regsql.exe <options>




SQL 连接选项





   
       
            选项
                说明
       

       
           
           

-?

           
               
           

在命令窗口中显示 Aspnet_regsql.exe 帮助文本。

           
       

       
           
           

-W

           
               
           

在向导模式下运行该工具。如果未指定任何命令行参数,那么这是默认设置。

           
       

       
           
           

-C <connection string>

           
               
           

指定要连接到正在运行 SQL Server 并且将安装或者已经安装数据库的计算机的连接字符串。如果您仅指定服务器 (-S) 和登录(-U 和 -P 或 -E)信息,则此选项不是必需的。

           
       

       
           
           

-S <server>

           
               
           

指定正在运行 SQL Server 并且将安装或者已安装数据库的计算机的名称。

           
       

       
           
           

-U <login ID>

           
               
           

要用来登录的 SQL Server 用户 ID。此选项还要求使用密码 (-P) 选项。如果要使用 Windows 凭据 (-E) 进行身份验证,则此选项不是必需的。

           
       

       
           
           

-P <password>

           
               
           

要用来登录的 SQL Server 密码。此选项还要求使用用户 ID (-U) 选项。如果要使用 Windows 凭据 (-E) 进行身份验证,则此选项不是必需的。

           
       

       
           
           

-E

           
               
           

使用当前登录用户的 Windows 凭据进行身份验证。

           
       

       
           
           

-sqlexportlonly <filename>

           
               
           

生成可用于添加或移除指定功能的 SQL 脚本文件。不执行指定的操作。

           
       

   



应用程序服务选项





   
       
            选项
                说明
       

       
           
           

-A all|m|r|p|c|w

           
               
           

添加对一项或多项 ASP.NET 应用程序服务的支持。可以同时或单独指定服务标识符。下列标识符用于 ASP.NET 应用程序服务。

           

all -- 所有的服务,包括由服务共享的通用表和存储过程。

           

m -- 成员资格

           

r -- 角色管理器

           

p -- 配置文件

           

c -- Web 部件个性化设置

           

w -- Web 事件

           
       

       
           
           

-R all|m|r|p|c|w

           
               
           

移除对一项或多项应用程序服务的支持。可以同时或单独指定服务标识符。下列标识符用于 ASP.NET 应用程序服务。

           

all -- 所有的服务,包括由服务共享的通用表和存储过程。

           

m -- 成员资格

           

r -- 角色管理器

           

p -- 配置文件

           

c -- Web 部件个性化设置

           

w -- Web 事件

           
       

       
           
           

-Q

           
               
           

在安静模式下运行该工具,并且在移除应用程序服务之前不进行确认。

           
       

       
           
           

-d <database>

           
               
           

指定要创建或修改以便与应用程序服务一起使用的数据库的名称。如果未指定数据库,则使用默认数据库名称“aspnetdb”。

           
       

   



SQL 缓存依赖项选项(用于 Microsoft SQL Server 7.0、Microsoft SQL Server 2000 和 SQL Server 2005)





   
       
            选项
                说明
       

       
           
           

-d <database>

           
               
           

指定要与 SQL 缓存依赖项一起使用的数据库的名称。还可以选择使用连接字符串选项 -C 指定该数据库。

           
       

       
           
           

-ed

           
               
           

为 SQL 缓存依赖项启用数据库。

           
       

       
           
           

-dd

           
               
           

为 SQL 缓存依赖项禁用数据库。

           
       

       
           
           

-et

           
               
           

为 SQL 缓存依赖项启用表。在参数字符串中还必须包括 -t 选项。

           
       

       
           
           

-dt

           
               
           

为 SQL 缓存依赖项禁用表。在参数字符串中必须包括 -t 选项。

           
       

       
           
           

-t <table>

           
               
           

指定要启用或禁用以便与 SQL 缓存依赖项一起使用的表名。此选项必须与 -et 或 -dt 选项一起使用。

           
       

       
           
           

-lt

           
               
           

列出所有为 SQL 缓存依赖项启用的表。

           
       

   



会话状态选项





   
       
            选项
                说明
       

       
           
           

-d <database>

           
               
           

指定要存储会话状态的数据库的名称。如果将 -sstype 设置为“c”,则必须使用此选项。

           
       

       
           
           

-ssadd

           
               
           

添加对 SQL Server 模式会话状态的支持。

           
       

       
           
           

-ssremove

           
               
           

移除对 SQL Server 模式会话状态的支持。

           
       

       
           
           

-sstype t|p|c

           
               
           

指定要使用的会话状态的类型:

           

t -- 临时。会话状态数据存储在 SQL Server 的 tempdb 数据库中。用于管理会话状态的存储过程安装在 SQL Server 的 ASPState 数据库中。如果重启 SQL,数据不会保持。这是默认设置。

           

p -- 持久。会话状态数据和存储过程均存储在 SQL Server 的 ASPState 数据库中。

           

c -- 自定义。会话状态数据和存储过程均存储在自定义数据库中。必须使用 -d 选项指定数据库名。

           
       

   



备注


使用 ASP.NET SQL Server 注册工具,您可以设置几种类型的选项。您可以指定 SQL 连接,指定使用 SQL Server 来管理信息的 ASP.NET 应用程序服务,指示将哪个数据库或表用于 SQL 缓存依赖项,以及添加或移除对使用 SQL Server 来存储过程和会话状态的支持。

几项 ASP.NET 应用程序服务依赖于提供程序来管理数据源中数据的存储和检索。每个提供程序都特定于数据源。ASP.NET 包括一个用于下列 ASP.NET 功能的 SQL Server 提供程序:


    *    
         

      成员资格(SqlMembershipProvider 类)。

    *    
         

      角色管理(SqlRoleProvider 类)。

    *    
         

      配置文件(SqlProfileProvider 类)。

    *    
         

      Web 部件个性化设置(SqlPersonalizationProvider 类)。

    *    
         

      Web 事件(SqlWebEventProvider 类)。

         


安装 ASP.NET 时,服务器的 Machine.config 文件包括一些配置元素,这些元素为依赖于提供程序的每个 ASP.NET 功能指定 SQL Server 提供程序。默认情况下,这些提供程序被配置为连接到 SQL Server Express 2005 的本地用户实例。如果更改提供程序使用的默认连接字符串,则必须先使用 Aspnet_regsql.exe 安装 SQL Server 数据库和用于所选功能的数据库元素,然后才能使用在计算机配置中配置的任何 ASP.NET 功能。如果使用 SQL 注册工具指定的数据库还不存在(如果未在命令行指定一个数据库,aspnetdb 将是默认数据库),则当前用户必须具有在 SQL Server 中创建数据库的权限,以及在数据库中创建架构元素的权限。

每个 SQL Server 提供程序都可以使用相同的 SQL Server 数据库来存储用于该特定功能的数据。每个功能都可以单独使用,也可以与其他功能结合使用。例如,可以单独使用角色管理,也可以将它与成员资格所管理的用户信息结合使用。

有关 SQL Server 提供程序和 ASP.NET 的更多信息,请参见实现成员资格提供程序、实现配置文件提供程序和实现角色提供程序。

SQL 缓存依赖项


ASP.NET 输出缓存的一项高级功能是 SQL 缓存依赖项。SQL 缓存依赖项支持两种不同模式的操作:第一种模式使用表轮询的 ASP.NET 实现,第二种模式使用 SQL Server 2005 的查询通知功能。SQL 注册工具可用于配置表轮询模式的操作。SQL 缓存依赖项使您可以缓存依赖于 SQL Server 表中数据的页。您可以配置 SQL Server 和 ASP.NET 以缓存页请求,降低服务器工作负荷,直到页所依赖的数据已在 SQL Server 中更新为止。对于相对保持静态的产品目录或客户注册信息等数据而言,SQL 缓存依赖项很有用。注意,当使用 SQL 缓存依赖项的 ASP.NET 表轮询模式时,您必须配置 SQL Server 以向 ASP.NET 提供关于依赖数据中的更改的适当通知,因此您需要具有配置服务器的管理特权。有关 SQL 缓存依赖项的更多信息,请参见演练:将 ASP.NET 输出缓存与 SQL Server 结合使用和演练:使用输出缓存增强网站性能。


会话状态


ASP.NET 会话状态是为了使您能在不同的源中方便地存储 ASP.NET 应用程序的用户会话数据而设计的。默认情况下,会话状态值和信息都存储在 ASP.NET 进程的内存中。另外,可以将会话数据存储在 SQL Server 数据库中,这种情况下会话数据可由多个 Web 服务器共享。有关会话状态的更多信息,请参见实现会话状态存储提供程序和会话状态模式。

如果使用 SQL 注册工具为会话状态指定的数据库还不存在,则当前用户必须具有在 SQL Server 中创建数据库的权限,以及在数据库中创建架构元素的权限。如果数据库不存在,则当前用户必须具有在现有数据库中创建架构元素的权限。

若要在 SQL Server 上安装会话状态数据库,请运行 Aspnet_regsql.exe 工具,并为命令提供下面的信息:


    *    
         

      使用 -S 选项指定 SQL Server 实例的名称。

    *    
         

      有权在运行 SQL Server 的计算机上创建数据库的帐户的登录凭据。使用 -E 选项,以使用当前登录的用户,或者使用 -U 选项指定用户 ID,并使用 -P 选项指定密码。

    *    
         

      用于添加会话状态数据库的 -ssadd 命令行选项。

         


默认情况下,不能使用 Aspnet_regsql.exe 工具在运行 SQL Server 2005 Express Edition 的计算机上安装会话状态数据库。有关使用 SQL Server 2005 Express Edition 存储会话状态的更多信息,请参见会话状态模式。



示例


可以在不使用任何命令行参数的情况下运行 Aspnet_regsql.exe,以运行一个引导您完成如下过程的向导:为 SQL Server 数据库指定连接信息,并为受支持的功能安装或移除数据库元素。还可以将 Aspnet_regsql.exe 作为命令行工具来运行,以便为各个功能指定要添加或移除的数据库元素。要指定 SQL 缓存依赖项的设置或对会话状态进行设置,必须使用命令行工具。

若要运行向导,请不带任何命令行参数运行 Aspnet_regsql.exe,如下面的示例所示。




 复制代码


C:/WINDOWS/Microsoft.NET/Framework/<versionNumber>/aspnet_regsql.exe



ASP.NET SQL 注册工具通常使用 -A 或 -R 选项来指定哪些功能使用 SQL Server 提供程序。-A 选项允许添加对一项或多项功能的支持,而 -R 选项允许移除一项功能。下面的命令使用 Windows 身份验证,在运行 SQL Server 的本地计算机上安装成员资格和角色管理器的数据库元素。




 复制代码


aspnet_regsql.exe -E -S localhost -A mr



若要设置 SQL 缓存依赖项,您需要具有管理特权,或管理帐户和密码。下面的命令为 Northwind 数据库中的 Employees 表启用 SQL 缓存依赖项。




 复制代码


aspnet_regsql.exe -S <Server> -U <Username> -P <Password> -ed -d Northwind -et -t Employees



下面的命令将在名为“SampleSqlServer”的 SQL Server 实例上创建一个名为 ASPState 的数据库,并指定会话数据也存储在 ASPState 数据库中。




 复制代码


aspnet_regsql.exe -S SampleSqlServer -E -ssadd -sstype p








[新闻]苹果已然取代微软地位成行业众矢之的
在.NET的平台上,加密MD5,SHA,DES
2008年7月10日 19:44
以前对加密这块总是觉得很高深,什么MD5,SHA,DES只是知道有这么个东西,可是一直不敢触及,通过这段时间的学习,才知晓,其实在.NET环境下加密已经做的非常的简单,作为一个开发的技术员来说,你只要有”拿来主义“的思想,就可以很简单的将它应用到你的项目中,至于具体的算法研究给那些研究算法的人去研究就好了,知道怎么回事就行了。



加密可以帮助保护数据不被查看和修改,并且可以帮助在本不安全的信道上提供安全的通信方式。例如,可以使用加密算法对数据进行加密,在加密状态下传输数据,然后由预定的接收方对数据进行解密。如果第三方截获了加密的数据,解密数据是很困难的。

 

在一个使用加密的典型场合中,双方(小红和小明)在不安全的信道上通信。小红和小明想要确保任何可能正在侦听的人无法理解他们之间的通信。而且,由于小红和小明相距遥远,因此小红必须确保她从小明处收到的信息没有在传输期间被任何人修改。此外,她必须确定信息确实是发自小明而不是有人模仿小明发出的。

加密用于达到以下目的:


    *    
         

      保密性:帮助保护用户的标识或数据不被读取。

    *    
         

      数据完整性:帮助保护数据不更改。

    *    
         

      身份验证:确保数据发自特定的一方。

         


为了达到这些目的,您可以使用算法和惯例的组合(称作加密基元)来创建加密方案。下表列出了加密基元及它们的用法。




   
       
            加密基元
                使用
       

       
           
           

私钥加密(对称加密)

           
               
           

对数据执行转换,使第三方无法读取该数据。此类型的加密使用单个共享的机密密钥来加密和解密数据。

           
       

       
           
           

公钥加密(不对称加密)

           
               
           

对数据执行转换,使第三方无法读取该数据。此类加密使用公钥/私钥对来加密和解密数据。

           
       

       
           
           

加密签名

           
               
           

通过创建对特定方唯一的数字签名来帮助验证数据是否发自特定方。此过程还使用哈希函数。

           
       

       
           
           

加密哈希

           
               
           

将数据从任意长度映射为定长字节序列。哈希在统计上是唯一的;不同的双字节序列不会哈希为同一个值。

           
       

   


私钥加密


私钥加密算法使用单个私钥来加密和解密数据。由于具有密钥的任意一方都可以使用该密钥解密数据,因此必须保护密钥不被未经授权的代理得到。私钥加密又称为对称加密,因为同一密钥既用于加密又用于解密。私钥加密算法非常快(与公钥算法相比),特别适用于对较大的数据流执行加密转换。

通常,私钥算法(称为块密码)用于一次加密一个数据块。块密码(如 RC2、DES、TripleDES 和 Rijndael)通过加密将 n 字节的输入块转换为加密字节的输出块。如果要加密或解密字节序列,必须逐块进行。由于 n 很小(对于 RC2、DES 和 TripleDES,n = 8 字节;n = 16 [默认值];n = 24;对于 Rijndael,n = 32),因此必须对大于 n 的数据值一次加密一个块。

基类库中提供的块密码类使用称作密码块链 (CBC) 的链模式,它使用一个密钥和一个初始化向量 (IV) 对数据执行加密转换。对于给定的私钥 k,一个不使用初始化向量的简单块密码将把相同的明文输入块加密为同样的密文输出块。如果在明文流中有重复的块,那么在密文流中将存在重复的块。如果未经授权的用户知道有关明文块的结构的任何信息,就可以使用这些信息解密已知的密文块并有可能发现您的密钥。若要克服这个问题,可将上一个块中的信息混合到加密下一个块的过程中。这样,两个相同的明文块的输出就会不同。由于该技术使用上一个块加密下一个块,因此使用了一个 IV 来加密数据的第一个块。使用该系统,未经授权的用户有可能知道的公共消息标头将无法用于对密钥进行反向工程。

可以危及用此类型密码加密的数据的一个方法是,对每个可能的密钥执行穷举搜索。根据用于执行加密的密钥大小,即使使用最快的计算机执行这种搜索,也极其耗时,因此难以实施。使用较大的密钥大小将使解密更加困难。虽然从理论上说加密不会使对手无法检索加密的数据,但这确实极大增加了这样做的成本。如果执行彻底搜索来检索只在几天内有意义的数据需要花费三个月的时间,那么穷举搜索的方法是不实用的。

私钥加密的缺点是它假定双方已就密钥和 IV 达成协议,并且互相传达了密钥和 IV 的值。并且,密钥必须对未经授权的用户保密。由于存在这些问题,私钥加密通常与公钥加密一起使用,来秘密地传达密钥和 IV 的值。

假设小红和小明是要在不安全的信道上进行通信的双方,他们可能按以下方式使用私钥加密。小红和小明都同意使用一种具有特定密钥和 IV 的特定算法(如 Rijndael)。小红撰写一条消息并创建要在其上发送该消息的网络流。接下来,她使用该密钥和 IV 加密该文本,并通过 Internet 发送该文本。她没有将密钥和 IV 发送给小明。小明收到该加密文本并使用预先商定的密钥和 IV 对它进行解密。如果传输的内容被人截获,截获者将无法恢复原始消息,因为截获者并不知道密钥或 IV。在这个方案中,密钥必须保密,但 IV 不需要保密。在一个实际方案中,将由小红或小明生成私钥并使用公钥(不对称)加密将私钥(对称)传递给对方。有关更多信息,请参见本主题后面的有关公钥加密的部分。

.NET Framework 提供以下实现私钥加密算法的类:


    *    
         

      DESCryptoServiceProvider

    *    
         

      RC2CryptoServiceProvider

    *    
         

      RijndaelManaged

    *    
         

      TripleDESCryptoServiceProvider

         



公钥加密


公钥加密使用一个必须对未经授权的用户保密的私钥和一个可以对任何人公开的公钥。公钥和私钥都在数学上相关联;用公钥加密的数据只能用私钥解密,而用私钥签名的数据只能用公钥验证。公钥可以提供给任何人;公钥用于对要发送到私钥持有者的数据进行加密。两个密钥对于通信会话都是唯一的。公钥加密算法也称为不对称算法,原因是需要用一个密钥加密数据而需要用另一个密钥来解密数据。

公钥加密算法使用固定的缓冲区大小,而私钥加密算法使用长度可变的缓冲区。公钥算法无法像私钥算法那样将数据链接起来成为流,原因是它只可以加密少量数据。因此,不对称操作不使用与对称操作相同的流模型。

双方(小红和小明)可以按照下列方式使用公钥加密。首先,小红生成一个公钥/私钥对。如果小明想要给小红发送一条加密的消息,他将向她索要她的公钥。小红通过不安全的网络将她的公钥发送给小明,小明接着使用该密钥加密消息。(如果小明在不安全的信道如公共网络上收到小红的密钥,则小明必须同小红验证他具有她的公钥的正确副本。)小明将加密的消息发送给小红,而小红使用她的私钥解密该消息。

但是,在传输小红的公钥期间,未经授权的代理可能截获该密钥。而且,同一代理可能截获来自小明的加密消息。但是,该代理无法用公钥解密该消息。该消息只能用小红的私钥解密,而该私钥没有被传输。小红不使用她的私钥加密给小明的答复消息,原因是任何具有公钥的人都可以解密该消息。如果小红想要将消息发送回小明,她将向小明索要他的公钥并使用该公钥加密她的消息。然后,小明使用与他相关联的私钥来解密该消息。

在一个实际方案中,小红和小明使用公钥(不对称)加密来传输私(对称)钥,而对他们的会话的其余部分使用私钥加密。

公钥加密具有更大的密钥空间(或密钥的可能值范围),因此不大容易受到对每个可能密钥都进行尝试的穷举攻击。由于不必保护公钥,因此它易于分发。公钥算法可用于创建数字签名以验证数据发送方的身份。但是,公钥算法非常慢(与私钥算法相比),不适合用来加密大量数据。公钥算法仅对传输很少量的数据有用。公钥加密通常用于加密一个私钥算法将要使用的密钥和 IV。传输密钥和 IV 后,会话的其余部分将使用私钥加密。

.NET Framework 提供以下实现公钥加密算法的类:


    *    
         

      DSACryptoServiceProvider

    *    
         

      RSACryptoServiceProvider

         



数字签名


公钥算法还可用于构成数字签名。数字签名验证发送方的身份(如果您信任发送方的公钥)并帮助保护数据的完整性。使用由小红生成的公钥,小红的数据的接收者可以通过将数字签名与小红的数据和小红的公钥进行比较来验证是否是小红发送了该数据。

为了使用公钥加密对消息进行数字签名,小红首先将哈希算法应用于该消息以创建消息摘要。该消息摘要是数据的紧凑且唯一的表示形式。然后,小红用她的私钥加密该消息摘要以创建她的个人签名。在收到消息和签名时,小明使用小红的公钥解密签名以恢复消息摘要,并使用与小红所使用的相同的哈希算法来散列消息。如果小明计算的消息摘要与从小红那里收到的消息摘要完全一致,小明就可以确定该消息来自私钥的持有人,并且数据未被修改过。如果小明相信小红是私钥的持有人,则他知道该消息来自小红。

请注意,由于发送方的公钥为大家所周知,并且它通常包含在数字签名格式中,因此任何人都可以验证签名。此方法不保守消息的机密;若要使消息保密,还必须对消息进行加密。

.NET Framework 提供以下实现数字签名算法的类:


    *    
         

      DSACryptoServiceProvider

    *    
         

      RSACryptoServiceProvider

         



哈希值


哈希算法将任意长度的二进制值映射为固定长度的较小二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希计算都将产生不同的值。要找到散列为同一个值的两个不同的输入,在计算上是不可能的。

消息身份验证代码 (MAC) 哈希函数通常与数字签名一起用于对数据进行签名,而消息检测代码 (MDC) 哈希函数则用于数据完整性。

双方(小红和小明)可按下面的方式使用哈希函数来确保数据的完整性。如果小红对小明编写一条消息并创建该消息的哈希,则小明可以在稍后散列该消息并将他的哈希与原始哈希进行比较。如果两个哈希值相同,则该消息没有被更改;如果值不相同,则该消息在小红编写它之后已被更改。为了使此系统发挥作用,小红必须对除小明外的所有人保密原始的哈希值。

.NET Framework 提供以下实现数字签名算法的类:


    *    
         

      HMACSHA1

    *    
         

      MACTripleDES

    *    
         

      MD5CryptoServiceProvider

    *    
         

      SHA1Managed

    *    
         

      SHA256Managed

    *    
         

      SHA384Managed

    *    
         

      SHA512Managed

         



随机数生成


随机数生成是许多加密操作不可分割的组成部分。例如,加密密钥需要尽可能地随机,以便使生成的密钥很难再现。加密随机数生成器必须生成无法以计算方法推算出(低于 p < .05 的概率)的输出;即,任何推算下一个输出位的方法不得比随机猜测具有更高的成功概率。.NET Framework 中的类使用随机数生成器生成加密密钥。

RNGCryptoServiceProvider 类是随机数生成器算法的实现。




[新闻]Intel 收购 Poky Linux ,为 MID 注入新的动力
PetShop4,错误提示:System.Web.Security.SqlMembershipProvider”要求一个与架构版本“1”兼容的数据
2008年7月9日 18:37
错误提示:

System.Web.Security.SqlMembershipProvider”要求一个与架构版本“1”兼容的数据库架构。但是,当前的数据库架构与此版本不兼容。您可能需要使用 aspnet_regsql.exe (在 framework 安装目录中提供)安装一个兼容的架构,或者将提供程序升级到一个较新的版本。



先在VS2005的命令行中运行asp_regsql,根据提示即可操作,然后再修改配置文件的连接字符串.

web.config中注意:

<add name="SQLMembershipProvider"

         type="System.Web.Security.SqlMembershipProvider"

          connectionStringName="SQLMembershipConnString"

          applicationName="mycard"

          enablePasswordRetrieval="false"

          enablePasswordReset="true"

          requiresQuestionAndAnswer="false" 

          requiresUniqueEmail="false"

          passwordFormat="Hashed"

          minRequiredPasswordLength="1"

          minRequiredNonalphanumericCharacters="0"

          passwordStrengthRegularExpression=""    />



=======

applicationName="mycard" ,此处为网站(或虚拟目录)名称




[新闻]雅虎将关闭社交网站Mash
PetShop4,错误提示:没有为 SQL 缓存通知启用数据库"MyCard"
2008年7月8日 17:29

在命令行下使用aspnet_regsql工具执行如下语句:

aspnet_regsql -S localhost -E -d DataBaseName -t TableName -et



[新闻]中国互联网战争局势图
为GridView加入全选
2008年7月7日 13:49

在Gridview中加入下列模板:

<asp:TemplateField HeaderText="全选">

        <HeaderTemplate>

                <asp:CheckBox ID="checkall" runat="server" Text="全选"

                        AutoPostBack="true" OnCheckedChanged="checkAll" />

         </HeaderTemplate>

          <ItemTemplate>

                   <asp:CheckBox ID="check" runat="server" Text="选择" />

            </ItemTemplate>    

</asp:TemplateField>

在CS文件中加入下列方法:

   protected void checkAll(object sender, EventArgs e)

  {

       CheckBox cb = (CheckBox) sender;

       if (cb.Text == "全选")

       {

           foreach (GridViewRow gvr in gvLessons.Rows)

           {

               CheckBox cb1 = (CheckBox)gvr.FindControl("check");

               cb1.Checked = cb.Checked;

           }

       }

    }






[新闻]开源多点触摸技术试运行
MemberShip的使用
2008年6月24日 12:07
摘要: 本文介绍了怎么在ASP.NET 2.0中使用Membership新特性,并且介绍了怎么两种不同的Membership的Provider:ActiveDirectoryMembershipProvider和SqlMembershipProvider,前者是基于微软活动目录服务存储用户信息的,或者是基于SQL SERVER存储的。2.0中的这个新机制大大减少了站点用户认证模块的代码量。目录:学习目的使  阅读全文

[新闻]国内软件外包高管集聚大连 探讨竞争与应对策略
PetShop 详解之一 系统架构设计
2008年6月22日 14:26
PetShop的系统架构设计

前言:PetShop是一个范例,微软用它来展示.Net企业系统开发的能力。业界有许多.Net与J2EE之争,许多数据是从微软的PetShop和Sun的PetStore而来。这种争论不可避免带有浓厚的商业色彩,对于我们开发人员而言,没有必要过多关注。然而PetShop随着版本的不断更新,至现在基于.Net 2.0的PetShop4.0为止,整个设计逐渐变得成熟而优雅,却又很多可以借鉴之处。PetShop是一个小型的项目,系统架构与代码都比较简单,却也凸现了许多颇有价值的设计与开发理念。本系列试图对PetShop作一个全方位的解剖,依据的代码是PetShop4.0,可以从链接http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/bdasamppet4.asp中获得。

一、PetShop的系统架构设计

在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。微软推荐的分层式结构一般分为三层,从下至上分别为:数据访问层、业务逻辑层(又或成为领域层)、表示层,如图所示:



图一:三层的分层式结构

数据访问层:有时候也称为是持久层,其功能主要是负责数据库的访问。简单的说法就是实现对数据表的Select,Insert,Update,Delete的操作。如果要加入ORM的元素,那么就会包括对象和数据表之间的mapping,以及对象实体的持久化。在PetShop的数据访问层中,并没有使用ORM,从而导致了代码量的增加,可以看作是整个设计实现中的一大败笔。

业务逻辑层:是整个系统的核心,它与这个系统的业务(领域)有关。以PetShop为例,业务逻辑层的相关设计,均和网上宠物店特有的逻辑相关,例如查询宠物,下订单,添加宠物到购物车等等。如果涉及到数据库的访问,则调用数据访问层。

表示层:是系统的UI部分,负责使用者与整个系统的交互。在这一层中,理想的状态是不应包括系统的业务逻辑。表示层中的逻辑代码,仅与界面元素有关。在PetShop中,是利用ASP.Net来设计的,因此包含了许多Web控件和相关逻辑。

分层式结构究竟其优势何在?Martin Fowler在《Patterns of Enterprise Application Architecture》一书中给出了答案:

1、开发人员可以只关注整个结构中的其中某一层;

2、可以很容易的用新的实现来替换原有层次的实现;

3、可以降低层与层之间的依赖;

4、有利于标准化;

5、利于各层逻辑的复用。

概括来说,分层式设计可以达至如下目的:分散关注、松散耦合、逻辑复用、标准定义。

一个好的分层式结构,可以使得开发人员的分工更加明确。一旦定义好各层次之间的接口,负责不同逻辑设计的开发人员就可以分散关注,齐头并进。例如UI人员只需考虑用户界面的体验与操作,领域的设计人员可以仅关注业务逻辑的设计,而数据库设计人员也不必为繁琐的用户交互而头疼了。每个开发人员的任务得到了确认,开发进度就可以迅速的提高。

松散耦合的好处是显而易见的。如果一个系统没有分层,那么各自的逻辑都紧紧纠缠在一起,彼此间相互依赖,谁都是不可替换的。一旦发生改变,则牵一发而动全身,对项目的影响极为严重。降低层与层间的依赖性,既可以良好地保证未来的可扩展,在复用性上也是优势明显。每个功能模块一旦定义好统一的接口,就可以被各个模块所调用,而不用为相同的功能进行重复地开发。

进行好的分层式结构设计,标准也是必不可少的。只有在一定程度的标准化基础上,这个系统才是可扩展的,可替换的。而层与层之间的通信也必然保证了接口的标准化。

“金无足赤,人无完人”,分层式结构也不可避免具有一些缺陷:

1、降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。

2、有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码。

前面提到,PetShop的表示层是用ASP.Net设计的,也就是说,它应是一个BS系统。在.Net中,标准的BS分层式结构如下图所示:



图二:.Net中标准的BS分层式结构

随着PetShop版本的更新,其分层式结构也在不断的完善,例如PetShop2.0,就没有采用标准的三层式结构,如图三:



图三:PetShop 2.0的体系架构

从图中我们可以看到,并没有明显的数据访问层设计。这样的设计虽然提高了数据访问的性能,但也同时导致了业务逻辑层与数据访问的职责混乱。一旦要求支持的数据库发生变化,或者需要修改数据访问的逻辑,由于没有清晰的分层,会导致项目作大的修改。而随着硬件系统性能的提高,以及充分利用缓存、异步处理等机制,分层式结构所带来的性能影响几乎可以忽略不计。

PetShop3.0纠正了此前层次不明的问题,将数据访问逻辑作为单独的一层独立出来:



图四:PetShop 3.0的体系架构

PetShop4.0基本上延续了3.0的结构,但在性能上作了一定的改进,引入了缓存和异步处理机制,同时又充分利用了ASP.Net 2.0的新功能MemberShip,因此PetShop4.0的系统架构图如下所示:



图五:PetShop 4.0的体系架构

比较3.0和4.0的系统架构图,其核心的内容并没有发生变化。在数据访问层(DAL)中,仍然采用DAL Interface抽象出数据访问逻辑,并以DAL Factory作为数据访问层对象的工厂模块。对于DAL Interface而言,分别有支持MS-SQL的SQL Server DAL和支持Oracle的Oracle DAL具体实现。而Model模块则包含了数据实体对象。其详细的模块结构图如下所示:



图六:数据访问层的模块结构图

可以看到,在数据访问层中,完全采用了“面向接口编程”思想。抽象出来的IDAL模块,脱离了与具体数据库的依赖,从而使得整个数据访问层利于数据库迁移。DALFactory模块专门管理DAL对象的创建,便于业务逻辑层访问。SQLServerDAL和OracleDAL模块均实现IDAL模块的接口,其中包含的逻辑就是对数据库的Select,Insert,Update和Delete操作。因为数据库类型的不同,对数据库的操作也有所不同,代码也会因此有所区别。

此外,抽象出来的IDAL模块,除了解除了向下的依赖之外,对于其上的业务逻辑层,同样仅存在弱依赖关系,如下图所示:



图七:业务逻辑层的模块结构图

图七中BLL是业务逻辑层的核心模块,它包含了整个系统的核心业务。在业务逻辑层中,不能直接访问数据库,而必须通过数据访问层。注意图中对数据访问业务的调用,是通过接口模块IDAL来完成的。既然与具体的数据访问逻辑无关,则层与层之间的关系就是松散耦合的。如果此时需要修改数据访问层的具体实现,只要不涉及到IDAL的接口定义,那么业务逻辑层就不会受到任何影响。毕竟,具体实现的SQLServerDAL和OracalDAL根本就与业务逻辑层没有半点关系。

因为在PetShop 4.0中引入了异步处理机制。插入订单的策略可以分为同步和异步,两者的插入策略明显不同,但对于调用者而言,插入订单的接口是完全一样的,所以PetShop 4.0中设计了IBLLStrategy模块。虽然在IBLLStrategy模块中,仅仅是简单的IOrderStategy,但同时也给出了一个范例和信息,那就是在业务逻辑的处理中,如果存在业务操作的多样化,或者是今后可能的变化,均应利用抽象的原理。或者使用接口,或者使用抽象类,从而脱离对具体业务的依赖。不过在PetShop中,由于业务逻辑相对简单,这种思想体现得不够明显。也正因为此,PetShop将核心的业务逻辑都放到了一个模块BLL中,并没有将具体的实现和抽象严格的按照模块分开。所以表示层和业务逻辑层之间的调用关系,其耦合度相对较高:



图八:表示层的模块结构图

在图五中,各个层次中还引入了辅助的模块,如数据访问层的Messaging模块,是为异步插入订单的功能提供,采用了MSMQ(Microsoft Messaging Queue)技术。而表示层的CacheDependency则提供缓存功能。这些特殊的模块,我会在此后的文章中详细介绍。



[新闻]Mac OS X 10.5.5 Build 9F23 测试版和 Safari 4 预览版
petshop4.0 详解之二 数据访问层之数据库访问设计
2008年6月22日 14:25

二、PetShop数据访问层之数据库访问设计


在系列一中,我从整体上分析了PetShop的架构设计,并提及了分层的概念。从本部分开始,我将依次对各层进行代码级的分析,以求获得更加细致而深入的理解。在PetShop 4.0中,由于引入了ASP.Net 2.0的一些新特色,所以数据层的内容也更加的广泛和复杂,包括:数据库访问、Messaging、MemberShip、Profile四部分。在系列二中,我将介绍有关数据库访问的设计。

在PetShop中,系统需要处理的数据库对象分为两类:一是数据实体,对应数据库中相应的数据表。它们没有行为,仅用于表现对象的数据。这些实体类都被放到Model程序集中,例如数据表Order对应的实体类OrderInfo,其类图如下:

ps09.gif

这些对象并不具有持久化的功能,简单地说,它们是作为数据的载体,便于业务逻辑针对相应数据表进行读/写操作。虽然这些类的属性分别映射了数据表的列,而每一个对象实例也恰恰对应于数据表的每一行,但这些实体类却并不具备对应的数据库访问能力。

由于数据访问层和业务逻辑层都将对这些数据实体进行操作,因此程序集Model会被这两层的模块所引用。

第二类数据库对象则是数据的业务逻辑对象。这里所指的业务逻辑,并非业务逻辑层意义上的领域(domain)业务逻辑(从这个意义上,我更倾向于将业务逻辑层称为“领域逻辑层”),一般意义上说,这些业务逻辑即为基本的数据库操作,包括Select,Insert,Update和Delete。由于这些业务逻辑对象,仅具有行为而与数据无关,因此它们均被抽象为一个单独的接口模块IDAL,例如数据表Order对应的接口IOrder:

ps10.gif

将数据实体与相关的数据库操作分离出来,符合面向对象的精神。首先,它体现了“职责分离”的原则。将数据实体与其行为分开,使得两者之间依赖减弱,当数据行为发生改变时,并不影响Model模块中的数据实体对象,避免了因一个类职责过多、过大,从而导致该类的引用者发生“灾难性”的影响。其次,它体现了“抽象”的精神,或者说是“面向接口编程”的最佳体现。抽象的接口模块IDAL,与具体的数据库访问实现完全隔离。这种与实现无关的设计,保证了系统的可扩展性,同时也保证了数据库的可移植性。在PetShop中,可以支持SQL Server和Oracle,那么它们具体的实现就分别放在两个不同的模块SQLServerDAL、OracleDAL中。

以Order为例,在SQLServerDAL、OracleDAL两个模块中,有不同的实现,但它们同时又都实现了IOrder接口,如图:

ps11.gif

从数据库的实现来看,PetShop体现出了没有ORM框架的臃肿与丑陋。由于要对数据表进行Insert和Select操作,以SQL Server为例,就使用了SqlCommand,SqlParameter,SqlDataReader等对象,以完成这些操作。尤其复杂的是Parameter的传递,在PetShop中,使用了大量的字符串常量来保存参数的名称。此外,PetShop还专门为SQL Server和Oracle提供了抽象的Helper类,包装了一些常用的操作,如ExecuteNonQuery、ExecuteReader等方法。

在没有ORM的情况下,使用Helper类是一个比较好的策略,利用它来完成数据库基本操作的封装,可以减少很多和数据库操作有关的代码,这体现了对象复用的原则。PetShop将这些Helper类统一放到DBUtility模块中,不同数据库的Helper类暴露的方法基本相同,只除了一些特殊的要求,例如Oracle中处理bool类型的方式就和SQL Server不同,从而专门提供了OraBit和OraBool方法。此外,Helper类中的方法均为static方法,以利于调用。OracleHelper的类图如下:

ps12.gif

对于数据访问层来说,最头疼的是SQL语句的处理。在早期的CS结构中,由于未采用三层式架构设计,数据访问层和业务逻辑层是紧密糅合在一起的,因此,SQL语句遍布与系统的每一个角落。这给程序的维护带来极大的困难。此外,由于Oracle使用的是PL-SQL,而SQL Server和Sybase等使用的是T-SQL,两者虽然都遵循了标准SQL的语法,但在很多细节上仍有区别,如果将SQL语句大量的使用到程序中,无疑为可能的数据库移植也带来了困难。

最好的方法是采用存储过程。这种方法使得程序更加整洁,此外,由于存储过程可以以数据库脚本的形式存在,也便于移植和修改。但这种方式仍然有缺陷。一是存储过程的测试相对困难。虽然有相应的调试工具,但比起对代码的调试而言,仍然比较复杂且不方便。二是对系统的更新带来障碍。如果数据库访问是由程序完成,在.Net平台下,我们仅需要在修改程序后,将重新编译的程序集xcopy到部署的服务器上即可。如果使用了存储过程,出于安全的考虑,必须有专门的DBA重新运行存储过程的脚本,部署的方式受到了限制。

我曾经在一个项目中,利用一个专门的表来存放SQL语句。如要使用相关的SQL语句,就利用关键字搜索获得对应语句。这种做法近似于存储过程的调用,但却避免了部署上的问题。然而这种方式却在性能上无法得到保证。它仅适合于SQL语句较少的场景。不过,利用良好的设计,我们可以为各种业务提供不同的表来存放SQL语句。同样的道理,这些SQL语句也可以存放到XML文件中,更有利于系统的扩展或修改。不过前提是,我们需要为它提供专门的SQL语句管理工具。

SQL语句的使用无法避免,如何更好的应用SQL语句也无定论,但有一个原则值得我们遵守,就是“应该尽量让SQL语句尽存在于数据访问层的具体实现中”。

当然,如果应用ORM,那么一切就变得不同了。因为ORM框架已经为数据访问提供了基本的Select,Insert,Update和Delete操作了。例如在NHibernate中,我们可以直接调用ISession对象的Save方法,来Insert(或者说是Create)一个数据实体对象:

public void Insert(OrderInfo order)

{

    ISession s = Sessions.GetSession();

    ITransaction trans = null;

    try

    {

    trans = s.BeginTransaction();

      s.Save( order);

      trans.Commit();

    }

    finally

    {

      s.Close();

    }

}

没有SQL语句,也没有那些烦人的Parameters,甚至不需要专门去考虑事务。此外,这样的设计,也是与数据库无关的,NHibernate可以通过Dialect(方言)的机制支持不同的数据库。唯一要做的是,我们需要为OrderInfo定义hbm文件。

当然,ORM框架并非是万能的,面对纷繁复杂的业务逻辑,它并不能完全消灭SQL语句,以及替代复杂的数据库访问逻辑,但它却很好的体现了“80/20(或90/10)法则”(也被称为“帕累托法则”),也就是说:花比较少(10%-20%)的力气就可以解决大部分(80%-90%)的问题,而要解决剩下的少部分问题则需要多得多的努力。至少,那些在数据访问层中占据了绝大部分的CRUD操作,通过利用ORM框架,我们就仅需要付出极少数时间和精力来解决它们了。这无疑缩短了整个项目开发的周期。

还是回到对PetShop的讨论上来。现在我们已经有了数据实体,数据对象的抽象接口和实现,可以说有关数据库访问的主体就已经完成了。留待我们的还有两个问题需要解决:

1、数据对象创建的管理

2、利于数据库的移植

在PetShop中,要创建的数据对象包括Order,Product,Category,Inventory,Item。在前面的设计中,这些对象已经被抽象为对应的接口,而其实现则根据数据库的不同而有所不同。也就是说,创建的对象有多种类别,而每种类别又有不同的实现,这是典型的抽象工厂模式的应用场景。而上面所述的两个问题,也都可以通过抽象工厂模式来解决。标准的抽象工厂模式类图如下:

ps13.gif

例如,创建SQL Server的Order对象如下:

PetShopFactory factory = new SQLServerFactory();

IOrder = factory.CreateOrder();

要考虑到数据库的可移植性,则factory必须作为一个全局变量,并在主程序运行时被实例化。但这样的设计虽然已经达到了“封装变化”的目的,但在创建PetShopFactory对象时,仍不可避免的出现了具体的类SQLServerFactory,也即是说,程序在这个层面上产生了与SQLServerFactory的强依赖。一旦整个系统要求支持Oracle,那么还需要修改这行代码为:

PetShopFactory factory = new OracleFactory();

修改代码的这种行为显然是不可接受的。解决的办法是“依赖注入”。“依赖注入”的功能通常是用专门的IoC容器提供的,在Java平台下,这样的容器包括Spring,PicoContainer等。而在.Net平台下,最常见的则是Spring.Net。不过,在PetShop系统中,并不需要专门的容器来实现“依赖注入”,简单的做法还是利用配置文件和反射功能来实现。也就是说,我们可以在web.config文件中,配置好具体的Factory对象的完整的类名。然而,当我们利用配置文件和反射功能时,具体工厂的创建就显得有些“画蛇添足”了,我们完全可以在配置文件中,直接指向具体的数据库对象实现类,例如PetShop.SQLServerDAL.IOrder。那么,抽象工厂模式中的相关工厂就可以简化为一个工厂类了,所以我将这种模式称之为“具有简单工厂特质的抽象工厂模式”,其类图如下:

ps14.gif

DataAccess类完全取代了前面创建的工厂类体系,它是一个sealed类,其中创建各种数据对象的方法,均为静态方法。之所以能用这个类达到抽象工厂的目的,是因为配置文件和反射的运用,如下的代码片断所示:

public sealed class DataAccess

{

 // Look up the DAL implementation we should be using

    private static readonly string path = ConfigurationManager.AppSettings[”WebDAL”];

    private static readonly string orderPath = ConfigurationManager.AppSettings[”OrdersDAL”];

 public static PetShop.IDAL.IOrder CreateOrder()

 {

         string className = orderPath + “.Order”;

         return (PetShop.IDAL.IOrder)Assembly.Load(orderPath).CreateInstance(className);

    }

}

在PetShop中,这种依赖配置文件和反射创建对象的方式极其常见,包括IBLLStategy、CacheDependencyFactory等等。这些实现逻辑散布于整个PetShop系统中,在我看来,是可以在此基础上进行重构的。也就是说,我们可以为整个系统提供类似于“Service Locator”的实现:

public static class ServiceLocator

{

 private static readonly string dalPath = ConfigurationManager.AppSettings[”WebDAL”];

    private static readonly string orderPath = ConfigurationManager.AppSettings[”OrdersDAL”];

 //……

 private static readonly string orderStategyPath = ConfigurationManager.AppSettings[”OrderStrategyAssembly”];

 public static object LocateDALObject(string className)

 {

  string fullPath = dalPath + “.” + className;

  return Assembly.Load(dalPath).CreateInstance(fullPath);

 }

public static object LocateDALOrderObject(string className)

 {

  string fullPath = orderPath + “.” + className;

  return Assembly.Load(orderPath).CreateInstance(fullPath);

 }

public static object LocateOrderStrategyObject(string className)

 {

  string fullPath = orderStategyPath + “.” + className;

  return Assembly.Load(orderStategyPath).CreateInstance(fullPath);

 }

 //……

}

那么和所谓“依赖注入”相关的代码都可以利用ServiceLocator来完成。例如类DataAccess就可以简化为:

public sealed class DataAccess

{

 public static PetShop.IDAL.IOrder CreateOrder()

 {

         return (PetShop.IDAL.IOrder)ServiceLocator. LocateDALOrderObject(”Order”);

    }

}

通过ServiceLocator,将所有与配置文件相关的namespace值统一管理起来,这有利于各种动态创建对象的管理和未来的维护。




[新闻]Mac OS X 10.5.5 Build 9F23 测试版和 Safari 4 预览版
petshop4.0 详解之三(PetShop数据访问层之消息处理)
2008年6月22日 14:23
三、PetShop数据访问层之消息处理



在进行系统设计时,除了对安全、事务等问题给与足够的重视外,性能也是一个不可避免的问题所在,尤其是一个B/S结构的软件系统,必须充分地考虑访问量、数据流量、服务器负荷的问题。解决性能的瓶颈,除了对硬件系统进行升级外,软件设计的合理性尤为重要。

在前面我曾提到,分层式结构设计可能会在一定程度上影响数据访问的性能,然而与它给设计人员带来的好处相比,几乎可以忽略。要提供整个系统的性能,还可以从数据库的优化着手,例如连接池的使用、建立索引、优化查询策略等等,例如在PetShop中就利用了数据库的Cache,对于数据量较大的订单数据,则利用分库的方式为其单独建立了Order和Inventory数据库。而在软件设计上,比较有用的方式是利用多线程与异步处理方式。

在PetShop4.0中,使用了Microsoft Messaging Queue(MSMQ)技术来完成异步处理,利用消息队列临时存放要插入的数据,使得数据访问因为不需要访问数据库从而提供了访问性能,至于队列中的数据,则等待系统空闲的时候再进行处理,将其最终插入到数据库中。

PetShop4.0中的消息处理,主要分为如下几部分:消息接口IMessaging、消息工厂MessagingFactory、MSMQ实现MSMQMessaging以及数据后台处理应用程序OrderProcessor。

从模块化分上,PetShop自始自终地履行了“面向接口设计”的原则,将消息处理的接口与实现分开,并通过工厂模式封装消息实现对象的创建,以达到松散耦合的目的。

由于在PetShop中仅对订单的处理使用了异步处理方式,因此在消息接口IMessaging中,仅定义了一个IOrder接口,其类图如下:

 ps01.gif

在对消息接口的实现中,考虑到未来的扩展中会有其他的数据对象会使用MSMQ,因此定义了一个Queue的基类,实现消息Receive和Send的基本操作:

public virtual object Receive()

{

      try

{

          using (Message message = queue.Receive(timeout, transactionType))

             return message;

      }

      catch (MessageQueueException mqex)

{

          if (mqex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)

             throw new TimeoutException();

                throw;

      }

}

public virtual void Send(object msg)

{

      queue.Send(msg, transactionType);

}

其中queue对象是System.Messaging.MessageQueue类型,作为存放数据的队列。MSMQ队列是一个可持久的队列,因此不必担心用户不间断地下订单会导致订单数据的丢失。在PetShopQueue设置了timeout值,OrderProcessor会根据timeout值定期扫描队列中的订单数据。

MSMQMessaging模块中,Order对象实现了IMessaging模块中定义的接口IOrder,同时它还继承了基类PetShopQueue,其定义如下:

public class order:PetShopQueue, PetShop.IMessaging.IOrder

方法的实现代码如下:

    public new orderInfo Receive()

    {

        // This method involves in distributed transaction and need Automatic Transaction type

        base.transactionType = MessageQueueTransactionType.Automatic;

        return (OrderInfo)((Message)base.Receive()).Body;

    }

    public orderInfo Receive(int timeout)

    {

        base.timeout = TimeSpan.FromSeconds(Convert.ToDouble(timeout));

        return Receive();

    }

    public void Send(OrderInfo orderMessage)

    {

        // This method does not involve in distributed transaction and optimizes performance using Single type

        base.transactionType = MessageQueueTransactionType.Single;

        base.Send(orderMessage);

    }

所以,最后的类图应该如下:

 ps02.gif

注意在Order类的Receive()方法中,是用new关键字而不是override关键字来重写其父类PetShopQueue的Receive()虚方法。因此,如果是实例化如下的对象,将会调用PetShopQueue的Receive()方法,而不是子类Order的Receive()方法:

PetShopQueue queue = new order();

queue.Receive();

从设计上来看,由于PetShop采用“面向接口设计”的原则,如果我们要创建Order对象,应该采用如下的方式:

IOrder order = new order();

order.Receive();

考虑到IOrder的实现有可能的变化,PetShop仍然利用了工厂模式,将IOrder对象的创建用专门的工厂模块进行了封装:

 ps03.gif

在类QueueAccess中,通过CreateOrder()方法利用反射技术创建正确的IOrder类型对象:

    public static PetShop.IMessaging.IOrder CreateOrder()

    {

        string className = path + ".Order";

        return PetShop.IMessaging.IOrder)Assembly.Load(path).CreateInstance(className);

    }

path的值通过配置文件获取:

private static readonly string path = ConfigurationManager.AppSettings["OrderMessaging"];

而配置文件中,OrderMessaging的值设置如下:

<add key="OrderMessaging" value="PetShop.MSMQMessaging"/>

之所以利用工厂模式来负责对象的创建,是便于在业务层中对其调用,例如在BLL模块中OrderAsynchronous类:

public class orderAsynchronous : IOrderStrategy

{       

    private static readonly PetShop.IMessaging.IOrder asynchOrder = PetShop.MessagingFactory.QueueAccess.CreateOrder();

    public void Insert(PetShop.Model.OrderInfo order)

{

        asynchOrder.Send(order);

    }

}

一旦IOrder接口的实现发生变化,这种实现方式就可以使得客户仅需要修改配置文件,而不需要修改代码,如此就可以避免程序集的重新编译和部署,使得系统能够灵活应对需求的改变。例如定义一个实现IOrder接口的SpecialOrder,则可以新增一个模块,如PetShop.SpecialMSMQMessaging,而类名则仍然为Order,那么此时我们仅需要修改配置文件中OrderMessaging的值即可:

<add key="OrderMessaging" value="PetShop.SpecialMSMQMessaging"/>

OrderProcessor是一个控制台应用程序,不过可以根据需求将其设计为Windows Service。它的目的就是接收消息队列中的订单数据,然后将其插入到Order和Inventory数据库中。它利用了多线程技术,以达到提高系统性能的目的。

在OrderProcessor应用程序中,主函数Main用于控制线程,而核心的执行任务则由方法ProcessOrders()实现:

    private static void ProcessOrders()

    {

        // the transaction timeout should be long enough to handle all of orders in the batch

        TimeSpan tsTimeout = TimeSpan.FromSeconds(Convert.ToDouble(transactionTimeout * batchSize));

        order order = new order();

        while (true)

        {

            // queue timeout variables

            TimeSpan datetimeStarting = new TimeSpan(DateTime.Now.Ticks);

            double elapsedTime = 0;

            int processedItems = 0;

            ArrayList queueOrders = new ArrayList();

            using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, tsTimeout))

            {

                // Receive the orders from the queue

                for (int j = 0; j < batchSize; j++)

                {

                    try

                    {

                        //only receive more queued orders if there is enough time

                        if ((elapsedTime + queueTimeout + transactionTimeout) < tsTimeout.TotalSeconds)

                        {

                            queueOrders.Add(order.ReceiveFromQueue(queueTimeout));

                        }

                        else

                        {

                            j = batchSize;   // exit loop

                        }

                        //update elapsed time

                        elapsedTime = new TimeSpan(DateTime.Now.Ticks).TotalSeconds - datetimeStarting.TotalSeconds;

                    }

                    catch (TimeoutException)

                    {

                        //exit loop because no more messages are waiting

                        j = batchSize;

                    }

                }

                //process the queued orders

                for (int k = 0; k < queueOrders.Count; k++)

                {

                    order.Insert((OrderInfo)queueOrders[k]);

                    processedItems++;

                    totalOrdersProcessed++;

                }

                //batch complete or MSMQ receive timed out

                ts.Complete();

            }

            Console.WriteLine("(Thread Id " + Thread.CurrentThread.ManagedThreadId + ") batch finished, " + processedItems + " items, in " + elapsedTime.ToString() + " seconds.");

        }

    }

首先,它会通过PetShop.BLL.Order类的公共方法ReceiveFromQueue()来获取消息队列中的订单数据,并将其放入到一个ArrayList对象中,然而再调用PetShop.BLL.Order类的Insert方法将其插入到Order和Inventory数据库中。

在PetShop.BLL.Order类中,并不是直接执行插入订单的操作,而是调用了IOrderStrategy接口的Insert()方法:

public void Insert(OrderInfo order)

{

    // Call credit card procesor

    ProcessCreditCard(order);

    // Insert the order (a)synchrounously based on configuration

    orderInsertStrategy.Insert(order);

}

在这里,运用了一个策略模式,类图如下所示:

 ps05.gif

在PetShop.BLL.Order类中,仍然利用配置文件来动态创建IOrderStategy对象:

private static readonly PetShop.IBLLStrategy.IOrderStrategy orderInsertStrategy = LoadInsertStrategy();

private static PetShop.IBLLStrategy.IOrderStrategy LoadInsertStrategy()

{

    // Look up which strategy to use from config file

    string path = ConfigurationManager.AppSettings["OrderStrategyAssembly"];

    string className = ConfigurationManager.AppSettings["OrderStrategyClass"];

    // Using the evidence given in the config file load the appropriate assembly and class

    return (PetShop.IBLLStrategy.IOrderStrategy)Assembly.Load(path).CreateInstance(className);

}

由于OrderProcessor是一个单独的应用程序,因此它使用的配置文件与PetShop不同,是存放在应用程序的App.config文件中,在该文件中,对IOrderStategy的配置为:

<add key="OrderStrategyAssembly" value="PetShop.BLL" />

<add key="OrderStrategyClass" value="PetShop.BLL.OrderSynchronous" />

因此,以异步方式插入订单的流程如下图所示:

 ps06.gif

Microsoft Messaging Queue(MSMQ)技术除用于异步处理以外,它主要还是一种分布式处理技术。分布式处理中,一个重要的技术要素就是有关消息的处理,而在System.Messaging命名空间中,已经提供了Message类,可以用于承载消息的传递,前提上消息的发送方与接收方在数据定义上应有统一的接口规范。

MSMQ在分布式处理的运用,在我参与的项目中已经有了实现。在为一个汽车制造商开发一个大型系统时,分销商Dealer作为.Net客户端,需要将数据传递到管理中心,并且该数据将被Oracle的EBS(E-Business System)使用。由于分销商管理系统(DMS)采用的是C/S结构,数据库为SQL Server,而汽车制造商管理中心的EBS数据库为Oracle。这里就涉及到两个系统之间数据的传递。

实现架构如下:

ps07.gif

     首先Dealer的数据通过MSMQ传递到MSMQ Server,此时可以将数据插入到SQL Server数据库中,同时利用FTP将数据传送到专门的文件服务器上。然后利用IBM的EAI技术(企业应用集成,Enterprise Application Itegration)定期将文件服务器中的文件,利用接口规范写入到EAI数据库服务器中,并最终写道EBS的Oracle数据库中。

上述架构是一个典型的分布式处理结构,而技术实现的核心就是MSMQ和EAI。由于我们已经定义了统一的接口规范,在通过消息队列形成文件后,此时的数据就已经与平台无关了,使得在.Net平台下的分销商管理系统能够与Oracle的EBS集成起来,完成数据的处理。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值