BlogProvider,BlogProviderCollection和blogprovidersection两个类用于定制提供程序
Blogservice类通过对他们的调用来实现对不同的提供程序使用一样的方法调用..
从web.config中读取以下内容
<BlogEngine>
<blogProvider defaultProvider="XmlBlogProvider">
<providers>
<add name="XmlBlogProvider" type="BlogEngine.Core.Providers.XmlBlogProvider"/>
<add name="MSSQLBlogProvider" type="BlogEngine.Core.Providers.MSSQLBlogProvider"/>
</providers>
</blogProvider>
</BlogEngine>
通过defaultProvider得到提供程序
由于使用了定制配置段,所以该段必须在使用前定义,还必须指定提供该定制段支持的类/类型。下面的代码列出了配置文件中完成这个操作所必需的项:
<configSections>
<sectionGroup name="BlogEngine">
<section name="blogProvider" requirePermission="false" type="BlogEngine.Core.Providers.BlogProviderSection, BlogEngine.Core" allowDefinition="MachineToApplication" restartOnExternalChanges="true"/>
</sectionGroup>
</configSections>
BlogEngine.Core.Providers.BlogProviderSection, BlogEngine.Core是访问该段时的处理程序
然后需要建立这个类
public class BlogProviderSection : ConfigurationSection
{
/// <summary>
/// A collection of registered providers.
/// </summary>
[ConfigurationProperty("providers")]
public ProviderSettingsCollection Providers
{
get { return (ProviderSettingsCollection)base["providers"]; }
}
/// <summary>
/// The name of the default provider
/// </summary>
[StringValidator(MinLength = 1)]
[ConfigurationProperty("defaultProvider", DefaultValue = "XmlBlogProvider")]
public string DefaultProvider
{
get { return (string)base["defaultProvider"]; }
set { base["defaultProvider"] = value; }
}
}
上面的示例给出了实现定制段所需的最少代码。在建立简单定制提供程序的其他部分之前,需要注意两个事项:第一,注意类继承了ConfigurationSection。ConfigurationSection类是.NET 2.0中新增的,以前这是通过实现IConfigurationSectionHandler接口来完成的,而该接口已在.NET 2.0中废弃。
定制段处理程序现在可以以编程或声明实现方式来执行。上面的示例使用了声明方式,让框架(以及指定的特性)完成许多工作。例如,在建立ConfigurationProperty特性,指定名称如defaultProvider时,实现方式会把配置文件中的defaultProvider数据绑定到类属性上,且无需编写代码。第二,还要注意使用特性指定验证器的功能。这也有助于减少定制代码的数量,但仍具备以健全的方式进行验证的功能。
BlogProvider抽象类继承至ProviderBase
BlogProviderCollection类继承至 ProviderCollection
为了说明他们的联系.先看下BlogService中的一个方法
private static void LoadProviders()
{
// Avoid claiming lock if providers are already loaded
if (_provider == null)
{
lock (_lock)
{
// Do this again to make sure _provider is still null
if (_provider == null)
{
// Get a reference to the <blogProvider> section
BlogProviderSection section = (BlogProviderSection)WebConfigurationManager.GetSection("BlogEngine/blogProvider");
//得到web.config默认提供程序
// Load registered providers and point _provider
// to the default provider
_providers = new BlogProviderCollection();
ProvidersHelper.InstantiateProviders(section.Providers, _providers, typeof(BlogProvider));
_provider = _providers[section.DefaultProvider];
//将默认的提供程序传递给_provider(BlogProvider类的实例)
if (_provider == null)
throw new ProviderException("Unable to load default BlogProvider");
}
}
}
}
//通过以上方法得到了提供程序,然后就可以通过以下代码调用.
/// <summary>
/// Returns a Post based on the specified id.
/// </summary>
public static Post SelectPost(Guid id)
{
LoadProviders();//到了提供程序
return _provider.SelectPost(id);//采用默认的提供程序调用数据访问层
}
对这个也是第一次接触,以下是关于定制提供程序的一篇文章,转载下希望能有帮助,下次将写关于post,page等业务层的学习过程
在建立定制提供程序时,必须完成许多步骤。本节将建立一个非常基本的定制提供程序,它只包含必须有的部分。
这里建立的定制提供程序使用Virtual Earth Map控件。假定编写一个Virtual Earth定制服务器控件,放在ASP.NET页面上。该控件显示地图上有趣的地点。可以把如何为一个应用程序获取有趣地点的知识硬编码到控件中,让它调用数据库,以加载这些地点。但将来,不做大量的工作,将无法使用其他数据源。
为了更好地重用该控件,我们将建立一个MVPHacksMapDataProvider,它有一个获取有趣地点的GetPoints方法。这个控件把当前的经度/纬度传送给该方法,数据提供程序就可以确定要返回的地点。
在下面的步骤中,我们将定义建立该基础结构所需的基本部分。
首先处理定制提供程序的配置功能。通过配置文件指定提供程序的功能是提供程序设计模式的一个重要部分。它允许方便地配置提供程序,且无需修改代码。为此,需要在配置文件中包含一个定制配置段,来定义和匹配提供程序。这一段将列出可用的提供程序和每个提供程序专用的选项,例如连接字符串。下面的示例显示了地图数据提供程序的配置段:
<configuration>
<MVPHacksMapDataProvider defaultProvider="SamplePointDataProvider">
<providers>
<add name="SamplePointDataProvider"
type="MVPHacks.SamplePointDataProvider,app_code" />
</providers>
</MVPHacksMapDataProvider>
</configuration>
上面的例子列出了使用提供程序设计模式指定提供程序所需的最少代码。在该例子中,定义了一个提供程序,defaultProvider把它标识为首选提供程序。
注意,上面的例子是一个定制配置段。为了不出现错误,必须定义这个段,还必须指定支持该定制段的定制类。第2步将完成这个操作。
如上一节所述,由于使用了定制配置段,所以该段必须在使用前定义,还必须指定提供该定制段支持的类/类型。下面的代码列出了配置文件中完成这个操作所必需的项:
<configSections>
<section name="CTCVEMapDataProvider"
type="MVPHacks.Common.MVPHacksMapDataProviderConfigSection,
mvphacks.common" />
</configSections>
MVPHacksMapDataProviderConfigSection类是访问该段时的段处理程序。这个类对该配置段中的项进行类型安全的访问。下一步就开始建立这个类。
与NET 1.1相比,.NET 2.0更容易建立定制配置段,且无需编写大量代码。下面示例中的代码说明了建立定制配置段所需的内容,该定制配置段匹配第1步中的段。这将提供一个定制段MVPHacksMapDataProvider,<provider>的子元素包含一个或多个提供程序定义。另外,它还支持defaultProvider特性,如果没有明确请求提供程序,该特性将指定要使用的提供程序。
using System;
using System.Configuration;
namespace MVPHacksCommon.CustomData
{
public class MVPHacksMapDataProviderConfigSection :
ConfigurationSection
{
[ConfigurationProperty("providers")]
public ProviderSettingsCollection Providers
{
get
{
return (ProviderSettingsCollection)base["providers"];
}
}
[ConfigurationProperty("defaultProvider",
DefaultValue=”MVPHacksNullMapDataProvider")]
[StringValidator(MinLength = 1)]
public string DefaultProvider
{
get
{
return (string)base["defaultProvider"];
}
set
{
base["defaultProvider"] = value;
}
}
}
}
上面的示例给出了实现定制段所需的最少代码。在建立简单定制提供程序的其他部分之前,需要注意两个事项:第一,注意类继承了ConfigurationSection。ConfigurationSection类是.NET 2.0中新增的,以前这是通过实现IConfigurationSectionHandler接口来完成的,而该接口已在.NET 2.0中废弃。
定制段处理程序现在可以以编程或声明实现方式来执行。上面的示例使用了声明方式,让框架(以及指定的特性)完成许多工作。例如,在建立ConfigurationProperty特性,指定名称如defaultProvider时,实现方式会把配置文件中的defaultProvider数据绑定到类属性上,且无需编写代码。第二,还要注意使用特性指定验证器的功能。这也有助于减少定制代码的数量,但仍具备以健全的方式进行验证的功能。
完整讨论定制配置段超出了本书的范围,但一定要注意.NET 2.0中的变化。这些变化更便于建立定制配置段。
下一步是创建一个继承自System.Configuration.Provider.ProviderBase的类,定义该定制提供程序的契约。
下面是几个注意要点:
● 提供程序继承自ProviderBase:这为各个提供程序提供了最低级的一致性。
● 类定义为抽象:这不是提供程序的实际实现方式,而只是契约。也就是说,可以在这个类中放置某些继承者可以使用的、帮助类型的方法。
● 类为契约定义了抽象方法:这是新提供程序上最干净的地方。在提供程序演化的过程中,可以指定带默认版本的方法,以确保与旧提供程序的兼容性。
● 使用抽象类而不是接口:契约肯定可以用接口定义,但随着时间的推移,接口会使提供程序变得僵化。这是因为在修改接口时,该接口的所有继承者和实现者都必须添加新方法或属性。抽象类在某种程度上不需要实现者添加方法或属性。
下面的示例代码建立了继承自ProviderBase的类:
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration.Provider;
namespace MVPHacksCommon.CustomData
{
public abstract class MVPHacksMapDataProvider : ProviderBase
{
public abstract List<MVPHacksMapDataLocation>
GetDataForRegion(double lattitude,
double longitude,double miles2show);
}
}
注意:
ProviderBase位于System.Configuration程序集的System.Configuration.Provider命名空间中。需要手动添加对该程序集的引用,因为它不会自动创建为类库项目的一部分。
不包含实现细节的一种方式是把某个内置的提供程序作为模式。注意它们是如何远离实现问题的。
如果所建立的提供程序仅在内部应用程序中使用,就可以从字面意义上解释它。如果是为第三方建立接口的ISV,从字面意义上解释它就更合适。
下一个要实现的类是一个静态类,它用作实际提供程序的外表。简单地说,这个类的作用是便于使用指定的提供程序作为配置项中的DefaultProvider。提供程序的用户只引用这个类上的静态方法。这个类负责查找配置段,使用其中的信息给指定为DefaultProvider的提供程序创建一个实例(一个副本):
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.Web.Configuration;
namespace MVPHacksCommon.CustomData
{
public static class MVPHacksMapData
{
static MVPHacksMapData()
{
SetupDefaultProvider();
}
private static string _initLockString = "MapDataProviderLock";
private static MVPHacksMapDataProvider _provider = null;
private static void SetupDefaultProvider()
{
lock (_initLockString)
{
if (_provider != null)
return;
MVPHacksMapDataProviderConfigSection providerConfig =
ConfigurationManager.GetSection("MapDataProvider")
as MVPHacksMapDataProviderConfigSection;
if (providerConfig == null)
return ;
ProviderSettings settings =
providerConfig.Providers[providerConfig.DefaultProvider];
_provider = ProvidersHelper.InstantiateProvider(settings,
typeof(MVPHacksMapDataProvider)) as
MVPHacksMapDataProvider;
}
}
public static List<MVPHacksMapDataLocation>
GetDataForRegion(double lattitude,
double longitude, double miles2show)
{
return _provider.GetDataForRegion(lattitude, longitude,
miles2show);
}
}
}
注意:
我们使用ProviderHelper获得提供程序的实例,ProviderHelper在System.Web.Configuration命名空间中。在InstantiateProvider方法中,ProviderHelper使用在配置文件中指定的类型创建提供程序的实例,并调用初始化方法。
最后一步是创建提供程序的具体实现代码。为此,创建一个继承自MVPHacksMapData Provider的类。在这个类中提供如何提取地图数据点的实现代码。在这个例子中,这是很简单的,我们把它们硬编码到两个指定的位置上。在更真实的例子中,有一个要从远程Web服务中提取出地点的版本,以及一个从本地文件或SQL Server中读取地点的版本。
using System;
using System.Collections.Generic;
using System.Text;
namespace MVPHacksCommon.CustomData
{
public class HardCodedMapDataProvider : MVPHacksMapDataProvider
{
public override List<MVPHacksMapDataLocation> GetDataForRegion
(double lattitude, double longitude, double miles2show)
{
List<MVPHacksMapDataLocation> list = new
List<MVPHacksMapDataLocation>();
MVPHacksMapDataLocation loc1 = new MVPHacksMapDataLocation();
loc1.Latitude = 33.35860433839252;
loc1.Longitude = -93.43521000572602;
loc1.Caption = "Somewhere in
list.Add(loc1);
return list;
}
}
}
这就完成了从头开始建立定制提供程序的基本部分。显然,这是一个非常简单的例子。举这么简单的例子是为了说明:建立自己的提供程序并不是一个非常复杂的过程。
考虑提供程序的最佳时间是在应用程序的设计阶段。但这并不意味着,如果有一个应用程序,就不能把定制提供程序引入其体系结构。实际上,使用提供程序的一种创造性方式是帮助把功能迁移到新版本中。例如,假定有一个应用程序执行营业税的计算。在这个例子中,应用程序只知道如何计算本县的税费。公司决定开始在全州中销售产品,因此必须使用更复杂的算法,根据各种因素计算税费。对此,首先是定义一个提供程序,它有一个CalculateTax方法,可以把当前的逻辑调整到一个LocalTaxCalcProvider类中。接着,建立一个使用该接口的StateWideTaxCalcProvider类。于是,应用程序很容易在两个提供程序之间切换,以支持测试。在部署时,要进行新的税费计算,只需修改配置,指定StateWideTaxCalcProvider。
这里的几个例子仅说明了如何在自己的应用程序中寻找机会,通过使用与ASP.NET小组所用的类似的扩展方式提高灵活性。这些扩展方式得到了广泛使用,所以定制提供程序的用户很熟悉它们。