这篇文章的思想的来源是Rob Howard半月前的一篇文章,《Provider Model Design Pattern and Specification, Part 1》,本来想等Rob H把Part II写完然后再一起总结一下的,可等啊等啊,估计这位哥们儿在忙着准备DevDay2004和做演讲,所以一直都没有等到Part II出来。不过Rob Howard在MSDN上的文章从来都是精品,而且这篇文章之前很长一段时间,由于忙着Whidbey的开发,Rob H已经很久时间没有在MSDN上的专栏撰写文章了,所以这篇文章出来的时候甚至被MS的人士称为“Return of the King”,呵呵。 言归正传。所谓Provider Modal,基本上都是指的“DataSource Provider Modal”。它是一种让你能够方便的提供多种数据源,并可以“动态”的在各个数据源间进行切换的一种模式。 在ASP.NET 2.0中,大量采用了Provider Modal模式。比如,Personalization和Membership是ASP.NET提供的内置的能够给开发人员极大方便的特性,它们能够自动保存用户的个性化信息,和维护站点用户信息。它们都需要一种存储方式,就是说,需要找一个数据源来保存他们的数据。但是这个数据源的提供方式,需要有非常大的灵活性、伸缩性、可定制性。比如,我的服务器可能没有安装SqlServer,只安装了MySql,但是我希望不管我的实际的数据库是什么类型(或者根本就没有条件安装大型数据库,而只能提供Access的方式进行保存),都能够作为Personalization和Membership所能使用的数据源,都能保存它们需要保存的数据。 这个时候,Provider Modal模式就可以大展身手了。首先,MemberShip对于能够保存它的数据的Data Provider提出一个要求,比如必须实现IMembershipProvider接口,而这个接口里面定义了保存MemberShip系统中的数据所需要实现的所有方法,比如“CreateUser(String username, String password, String email, out MembershipCreateStatus status)”用来创建新用户,“Boolean ChangePassoword(String name, String oldpassword, String newpassword)”用来修改用户密码。我们要做的,就是针对MySql写一个MySqlMembershipProvider,实现IMembershipProvider要我们实现的所有接口,然后在web.config文件将我们写的这个MySqlMembershipProvider指定给MemberShip用。而对于MemberShip系统来说,它不用关心倒是是谁实现了IMembershipProvider,它只是根据web.config里面的设置,载入那个具体的实现IMembershipProvider的对象,然后调用IMembershipProvider定义的接口方法就可以了。这样我们就拥有了极大的灵活性,可以根据自己的要求定制满足自己需要的Data Provider。 上面所说的,就是Provider Modal模式了。在很多的场合,在我们需要一个很大的灵活性的数据存储方式多样化的场合,我们可以应用这个模式,让我们的系统变得灵活而具有可扩展性。能够想到的包括Log纪录、Cache保存、用户State状态保存等等,只要我们开始做的时候就明智的应用Provider Modal模式,那么也就给了以后扩展的机会。 好像很简单,呵呵,但是掌握更多的实现规范才能更好的实现它。更多的细节和实现规则,请参看Rob Howard的文章。上面ASP.NET 2.0 Personalization和Membership特性,来自《A First Look At ASP.NET 2.0》。 现在就可以得到的Provider Modal的极佳范例,ASP.NET Forum 2.0,现在仍处于Alpha阶段,预计月底发布Beta和Final版本。 |
-- 作者:soyzhc -- 发布时间:2005-7-28 23:20:26 -- 在Whidbey中实现Provider 本文由sam1111授权ASPCOOL.COM发表,未经作者许可,严禁转载。 Asp.Net 2.0(codename Whidbey)通过Provider模式为用户验证、角色管理等方面提供了非常强大易用的框架模型。Whidbey中提供了一个Asp.Net configuration工具,通过它可以非常容易地配置用户信息数据库,管理角色等等,再与新加入的Security控件配合,几乎不用写什么代码就能够实现用户验证和角色管理功能。关于这些控件和配置工具的具体使用,可以参考这篇文章:使用更精简的代码保证 ASP.NET 应用程序的安全 但是在PDC Preview版本的Whidbey中,这个配置工具的功能还不是很完善。从我使用的情况来看,它目前还只能创建和连接自己的Demo用的Access数据库,不能连接SQL Server数据库进行扩展。因此,为了能够连接SQL Server,我们必须提供我们自己的Providers。这里以连接IBuySpy的Portal数据库为例来说明如何实现一个Membership Provider。 为了搞清楚如何实现我们自己的Membership Provider,有必要先看看Whidbey默认使用的Membership Provider是如何做的。在machine.config配置文件中,Whidbey使用类似下面这样的配置实现: <membership defaultProvider="AspNetAccessProvider" userIsOnlineTimeWindow="15" > <providers> <add name="AspNetSqlProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=1.2.3400.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="LocalSqlServer" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" description="Stores and retrieves membership data from the local Microsoft SQL Server database" /> <add name="AspNetAccessProvider" type="System.Web.Security.AccessMembershipProvider, System.Web, Version=1.2.3400.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="AccessFileName" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" description="Stores and retrieves membership data from the local Microsoft Access database file" /> </providers> </membership> 关于这段配置文件的更详细解说,可以参考《A First Look at ASP.NET v. 2.0》。 可以看出,Whidbey默认使用SqlMembershipProvider或者AccessMembershipProvider来进行用户验证和管理。这两个Provider实现了IProvider和IMembershipProvider接口,实际上这两个接口也是每个MembershipProvider所必需的,其中IProvider负责Provider的初始化,而IMembershipProvider则实现MembershipProvider的主要功能。它们的定义如下: namespace System.Configuration.Provider { public interface IProvider { public string Name { get; } public void Initialize(string name, System.Collections.Specialized.NameValueCollection config); } } namespace System.Web.Security { public interface IMembershipProvider { public bool ChangePassword(string name, string oldPwd, string newPwd); public bool ChangePasswordQuestionAndAnswer(string name, string password, string newPwdQuestion, string newPwdAnswer); public System.Web.Security.MembershipUser CreateUser( string username, string password, string email, out System.Web.Security.MembershipCreateStatus status); public bool DeleteUser(string name); public System.Web.Security.MembershipUserCollection GetAllUsers(); public int GetNumberOfUsersOnline(); public string GetPassword(string name, string answer); public System.Web.Security.MembershipUser GetUser(string name, bool userIsOnline); public string GetUserNameByEmail(string email); public string ResetPassword(string name, string answer); public void UpdateUser(System.Web.Security.MembershipUser user); public bool ValidateUser(string name, string password); public string ApplicationName {get; set;} public bool EnablePasswordReset { get;} public bool EnablePasswordRetrieval { get;} public bool RequiresQuestionAndAnswer { get;} } } 现在可以动手来实现我们自己的MembershipProvider了: public class MyMembershipProvider : IProvider, IMembershipProvider { …… } 验证功能是必需的: public bool ValidateUser (string name, string password) { string connectStr = ConfigurationSettings.ConnectionStrings["PortalData"]; SqlConnection myConnection = new SqlConnection (connectStr); SqlCommand myCommand = new SqlCommand ("UserLogin", myConnection); myCommand.CommandType = CommandType.StoredProcedure; // Add Parameters to SPROC SqlParameter parameterEmail = new SqlParameter ("@Email", SqlDbType.NVarChar, 100); parameterEmail.Value = name; myCommand.Parameters.Add (parameterEmail); SqlParameter parameterPassword = new SqlParameter ("@Password", SqlDbType.NVarChar, 20); parameterPassword.Value = password; myCommand.Parameters.Add (parameterPassword); SqlParameter parameterUserName = new SqlParameter ("@UserName", SqlDbType.NVarChar, 100); parameterUserName.Direction = ParameterDirection.Output; myCommand.Parameters.Add (parameterUserName); // Open the database connection and execute the command myConnection.Open (); myCommand.ExecuteNonQuery (); myConnection.Close (); if ((parameterUserName.Value != null) && (parameterUserName.Value != System.DBNull.Value)) return true; return false; } 现在在web.config中可以这样配置connectionString了: <connectionStrings> <add name="BugDepotData" connectionString="Data Source=(local);Trusted_Connection=true;Database=Portal" /> </connectionStrings> 这样,我们自己的一个简单的MembershipProvider就基本上完成了。接下来需要配置web.config,让需要Provider服务的控件能够认识它: <membership> <providers> <add name="MyMembershipProvider" type="MyMembershipProvider" appName="/" /> </providers> </membership> 这段设置是参考machine.config而来的,其中type属性的值是这样的字符串: type="ProviderType, Assembly, Version, Culture, PublicKeyToken" 由于我们的MyMembershipProvider放在/Code目录下,并不是在单独的Assembly中,因此只需要指出ProviderType就行了。 这样,一个具有验证功能的Provider就完成了,现在可以在页面上放一个新的Security控件,比如Login控件,并指定它的MembershipProperty为MyMembershipProvider(或者也可以设置membership的defaultProvider属性为MyMembershipProvider),打开Forms验证,试试是不是已经能够成功登陆了?J |
-- 作者:soyzhc -- 发布时间:2005-7-28 23:25:49 -- 第一次写可能写的比较乱,希望谅解,另外,本文只写了鄙人的学习心得,并不是2.0全部的特性。 这样使得2.0中Code Behind中的代码结构更清晰,干净,容易阅读。 Cross Page Posting
看一下1.1和2.0的差别
1.1时,当用户提交时,被送回原有form的页。
2.0中,开发者可以决定form的数据到底要送到哪里,PostBackUrl属性。如果不做说明,被送回原来的form是默认的。例如当你创建一个包含不同form的多页的向导时,当用户需要返回时,他可以很快地得到页面,而且不用重新填写,通过PreviousPage object。 |
-- 作者:soyzhc -- 发布时间:2005-7-29 0:36:36 -- Provider Model DNN uses the provider model extensively. A provider pattern enables you to abstract out certain functionality. For example in the architectural diagram (see Figure x) you can see how there is a Abstract Data Provider between the Business Components, and the Concrete Data Provider, this enables you to plug in different providers without having to modify or recompile the core code within DNN. DNN uses a provider pattern extensively in it’s architecture. We talked about the database provider, but several other features use this pattern as well. Security and Membership Provider Text/HTML Provider Logging Provider Scheduler Friendly URLsDNN广泛地使用了provider模式。Provider模版能够让你抽象出一定的功能。例如在架构图中可以看到在BLL和实际数据库之间有个抽象的数据provider,这样就可以使你使用不同的provider而不用重新编译DNN。
As mentioned, provider patterns enable you to abstract out certain functions, but the actual physical providers are then defined in the web.config. For example, in DNN if you open the web.config you will see a section for the providers:
已经提到了provider模版使你能够抽象一定的功能,但实际应用的provider是在web.config中定义。例如打开web.config可以看到这个部分;
By reviewing the web.config definition you can see that each provider is defined by a key, and then specific configuration properties are specified in order to define which physical provider to use. For example in the data section you see the following:
复习web.config的定义会发现,每个provider都由一个关键字定义,特定的设置将指定哪个provier将被使用。例如:
The defaultProvider is defined as SQLDataProvider, then within the data key you can see the configuration information for the SQLDataProvider:
缺省定义是SQLDataProvider,里面能看到具体配置。
You can see within the provider section of the web.config is the actual physical database information. You could have as many providers as you want defined here, and thentch the defaultProvider value to point to a new physical database provider. Of course you would need to have a provider developed and loaded within your bin folder in order for it to be used. In addition to having a provider for DNN, you would also need to have a provider developed for your module that uses the same physical database as DNN.
可以在web.config区看到真正的数据库信息。你可以无限定义provider,并且设置defaultProvider值来切换不同的数据库。
你应当将包括bin文件夹的开发好的provider载入,才能在这里使用。你也需要开发一个使用DNN相同数据库的自己的provider。
Quick Tip: Learn More About Provider Patterns
Rob Howard details out the Provider Pattern in a two part series at Microsoft’s MSDN site:
Provider Model Design Pattern and Specification, Part 1:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspnet/html/asp02182004.asp
Provider Design Pattern, Part 2:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspnet/html/asp04212004.asp?frame=true Folder Structure DotNetNuke strives to logically structure the folders within the application root folder. The following list provides the folders under the root folder that are important to your development efforts, and what they contain.
DNN在根目录力求逻辑化组织文件夹。 /Admin – Contains interfaces to the various administrative functions within DNN, for example, the scheduler, tab management, search manager, and any interface that is to be secured and accessible by a portal host or admin. 和DNN不同管理功能接入的容器,例如日程,栏目管理,搜索管理,以及其他。 /App_GlobalResources – Contains application specific data like time zone information, and application settings. 包含特定的程序例如时区信息,程序设置。 /bin – Contains the compiled assemblies of your DNN solution, and supporting assemblies. 包含DNN编译好的程序集,和其他支持的程序集。 /Components – Contains core functionality for DNN. DNN的核心功能。 /controls – Contains the various controls for enhancing the user interface of DNN, for example the Text/HTML provider is located within this folder. 包含各种加强DNN用户界面的各种控件,例如tezt/html就在这里。 /DesktopModules – Contains all module projects for DNN. This is where you would place your directory for your module project. 包含所有DNN模块项目。这里你可以设置自己的模块项目。 /HttpModules – All HTTPModule projects are contained in here, for example, the exception handler, URLRewriter, Scheduler, and others. 包含所有的HTTPModule项目。 /images – Contains any images used by DNN such as icons. DNN相关图片,图标。 /js – Contains any client side scripts in use by DNN, for example the calendar popup control. DNN客户脚本,例如弹出日期控件。 /portals – Contains the default portal folder, and will contain any portal folders for newly created portals. This provides any new child portal with it’s own personal folder for storing files, and portal skins. Portal folders are identified by a unique integer value which matches up with the Portal ID field value in the Portals table in the DNN database. 包含默认门户文件夹,也会包含新建立的门户站点的文件夹。提供了新子站点的自己的文件夹,皮肤等。 文件夹使用一个和DNN数据库中portals表中portal ID对应的数字作为名称。 /Providers – Contains the providers for your DNN portal, for example the database providers are located in a sub directory off of this folder. 包含了DNN的providers,例如数据库providers。 /Resources /Web references – This folder contains references for Web services, currently the exceptions Web service which allows a portal admin to optionally notify the DNN core team about errors being generated by the portal. 包含web服务的引用,目前的异常web服务在站点出错的时候会通知DNN核心团队。 Beginning Module Development Now that we have covered what modules are, and how they interface with DNN, let’s get started developing modules. In the next sections we will cover how to set up a Visual Studio.Net project, and begin development.
开始开发模块
经过前面的学习,我们可以开始开发模块了。在下面的部分我们将了解如何设置VisualStudio.Net项目,然后开始开发模块。 Configuring Your Visual Studio.NET Project Some basic assumptions of this guide are that you have a development machine configured with a default DNN installation within a virtual directory. You should also have some basic knowledge of developing ASP.NET applications in Visual Studio.NET. We are going to build off our default installation of DNN and add our module projects to the solution. By adding to the main DNN solution you ensure you are compiling to the DNN bin directory, and enable debugging for your module project.
配置你的VS项目
假定你已经配置好开发环境,安装了默认的DNN。你需要一些使用VS开发asp.net的基础知识。我们将建立DNN的默认安装,并且添加你的模块项目到解决方案。加入方案时确认编译到DNN的bin目录,并能够调试模块项目。
Creating the Module Project
In order to create our module project you should have your DNN solution open, and we’ll need to add a new project to the solution in order to begin. There are various methods for creating modules for DNN, but we prefer to configure a separate project for module creation and then compile the assemblies within each module’s own bin folder. The following procedure provides a method for configuring a portal module project in Visual Studio.NET.
创建模块项目
打开DNN解决方案。有多种方式给DNN添加一个模块,但是我们习惯建立单独的项目,然后在模块自己的bin文件夹中编译程序。 Create a new class project, be sure to use a logical naming structure. For example: CompanyName.ModuleName. By using this format you ensure your module will not conflict with modules developed by other companies or developers. 创建一个新的类库项目,确认使用一个逻辑化的命名结构。例如:公司名.模块名。使用这种格式命名将确保你的模块不会和其他开发商的模块混淆。 When creating the new project folder, create a folder off of the DotNetNuke Root\\DesktopModules\\ directory. 建立新项目目录时,选择DotNetNuke Root\\DesktopModules\\ directory这里建立。 Clear any namespace from the project properties. Right click on properties of the project, under general clear the root namespace box. 在项目属性中清除命名空间。右键项目,在通用/常规中,清除根命名空间。 Add a reference to the DotNetNuke project in your new module project. 在你的新项目中添加DNN项目的引用。 In the BuildSupport project in the \\Solutions\\DotNetNuke.DesktopModules\\BuildSupport\\ directory add a reference to your project. By adding the reference to the BuildSupport project will take the references from your solution to be built within the main DotNetNuke bin directory. 在BuildSupport项目中添加新建项目的引用。这样可以使你的方案被生成到DNN主bin目录中。
Figure 8 – Class Project Properties Dialog
Now that your project has been created we will create some user controls for your module interface. A simple module can be as basic as a view control to display an interface for your user, and then a settings control for specifying unique values that are specific for a module instance.
现在项目已经建立了,然后为你的模块界面创建一些用户控件。对用户来说一个模块的浏览控件是基本的,然后是设置控件,对模块实例来说有唯一值。
This is one area of difficulty when developing module projects for DNN. Since we want to be able to see the results of our development within the portal, the method to accomplish this is by using a class project which allows you in Visual Studio.NET to change the compilation path. Since we are working within a class project the ability to create user controls in Visual Studio.NET is limited and only available when you’re in a Web project. As of this writing, this author has included the Quick Tip below to point you to templates that will make the creation of the controls easier. For the purposes of this guide, we will manually create an item and add our code.
这里是个难点。由于我们想看到在门户开发中的结果,所以使用了类库项目,这样就可以在vs中改变编译路径。由于我们使用的是类库项目所以不能直接添加用户控件,只有使用web项目时才可以。所以可以参考下面的快速提示使用模版来建立用户控件。在这里我们手工添加控件和代码。
In our example we work with the Survey module that is included in the DNN distribution. This module is located within the /DesktopModules/Survey directory included in the distribution.
我们的例子是使用DNN中的Survey模块。它在/DesktopModules/Survey目录中。
You see some controls, as well as some class files within this folder. Initially when starting a project, you will need to create a few user controls for your user to interact with your module, and for your administrators to configure some module instance settings.
你将看到一些控件和类。开始一个项目的时候,你需要建立几个用户控件和你的模块交互,并且为你的管理员配置一些模块实例设置。
Quick Tip: Ease DNN File Creation
In this guide we cover creating a module project from scratch; you can streamline this development process by using resources available on the Web. These we’re initially targeted at DNN 2.x, but should also work for DNN 3.x. Try using DNN Project Templates available http://dnnjungle.vmasanas.net/Default.aspx?tabid=28 for creating your module projects, and controls.
The Data Provider project is for developing the methods for interfacing with the physical database. In this guide we discuss SQL Server 2000 as our physical database provider, but your actual provider could be particularly any database such as Access, Oracle, or even MySQL. One of the big advantages of the DNN architecture is a provider model pattern, which enables to you to plug in any provider you wish for the physical database provider. We will discuss the provider pattern later in this guide.
建立数据provider项目
provider项目是为了和实际数据库交互而开发的。在这里我们使用Sql Server2000作为我们的provider。但你的provider可以是任意数据库例如Access,Oracle,甚至是MySql。DNN架构的最大特点之一就是provider模块模式,这样可以使用任意物理数据库的provider。稍后我们将讨论provider模式。
In module development you create a separate project for each physical dataprovider. You do this similar to the way you configured your module project.
在模块开发中需要为每个物理数据provider开发独立的项目。建立步骤和建立模块项目是 类似的。 Create a new class project, be sure to use a logical naming structure. For example: CompanyName.ModuleName.SQLDataProvider. Again, this will avoid naming conflicts with other modules, and keeps you within the naming structure of the module that this provider is going to support. When creating the new project folder, create a folder off of the DotNetNuke Root\\DesktopModules\\ModuleName\\ directory, call this directory “Providers”, and create a subdirectory for each provider type you will develop, for example: Clear any namespace from the project properties. Right click on properties of the project, under general clear the root namespace box. Now add project references to the main DotNetNuke and CompanyName.ModuleName projects. Add a reference to the BuildSupport project as we did in the module setup.
Once both projects are configured they should look similar to Figure 9. 完成后如图9所示。 |