在使用 Membership 的时候可以为同一种操作方法定义多种行为,而具体使用哪种行为只需要在 Web.Config 中定义即可。
这样可以极大的促进了系统的灵活性,可是 Membership 这种 Provider 服务是怎么设计的呢?查了一些资料,也查看了 .Framework 2.0 的反编译源码,最终还是在 MSDN 上的一篇英文资料中找到了答案。
设计这种模式,似乎并不是那么容易,需要设计许多类方可。
构建基于Provider的自定义服务
下面是一个基本Provider的自定义服务的示例,它公开了两个操作方法“RetrieveImage”和“SaveImage”。它有可以会使用不同的数据库,这样可以定义多种处理方法。只需要在 Web.Config 中进行配置,就可以让系统调用相应的行为来进行处理。
1、 首先构建一个 ImageProvider 它继承了 ProviderBase 类。
public abstract class ImageProvider : ProviderBase
{
// Properties
public abstract string ApplicationName { get; set; }
public abstract bool CanSaveImages { get; }
// Methods
public abstract Image RetrieveImage (string id);
public abstract void SaveImage (string id, Image image);
}
public class ImageProviderCollection : ProviderCollection
{
public new ImageProvider this[string name]
{
get { return (ImageProvider) base[name]; }
}
public override void Add(ProviderBase provider)
{
if (provider == null)
throw new ArgumentNullException("provider");
if (!(provider is ImageProvider))
throw new ArgumentException
("Invalid provider type", "provider");
base.Add(provider);
}
}
2、 我们先定义一个使用 SQL Server 的处理方法。
[SqlClientPermission (SecurityAction.Demand, Unrestricted=true)]2
public class SqlImageProvider : ImageProvider3
{4
private string _applicationName;5
private string _connectionString;6

7
public override string ApplicationName8
{9
get { return _applicationName; }10
set { _applicationName = value; }11
}12

13
public override bool CanSaveImages14
{15
get { return false; }16
}17

18
public string ConnectionStringName19
{20
get { return _connectionStringName; }21
set { _connectionStringName = value; }22
}23

24
public override void Initialize (string name,25
NameValueCollection config)26
{27
// Verify that config isn't null28
if (config == null)29
throw new ArgumentNullException ("config");30

31
// Assign the provider a default name if it doesn't have one32
if (String.IsNullOrEmpty (name))33
name = "SqlImageProvider";34

35
// Add a default "description" attribute to config if the36
// attribute doesn't exist or is empty37
if (string.IsNullOrEmpty (config["description"])) {38
config.Remove ("description");39
config.Add ("description",40
"SQL image provider");41
}42

43
// Call the base class's Initialize method44
base.Initialize(name, config);45

46
// Initialize _applicationName47
_applicationName = config["applicationName"];48

49
if (string.IsNullOrEmpty(_applicationName))50
_applicationName = "/";51

52
config.Remove["applicationName"];53

54
// Initialize _connectionString55
string connect = config["connectionStringName"];56

57
if (String.IsNullOrEmpty (connect))58
throw new ProviderException59
("Empty or missing connectionStringName");60

61
config.Remove ("connectionStringName");62

63
if (WebConfigurationManager.ConnectionStrings[connect] == null)64
throw new ProviderException ("Missing connection string");65

66
_connectionString = WebConfigurationManager.ConnectionStrings67
[connect].ConnectionString;68

69
if (String.IsNullOrEmpty (_connectionString))70
throw new ProviderException ("Empty connection string");71

72
// Throw an exception if unrecognized attributes remain73
if (config.Count > 0) {74
string attr = config.GetKey (0);75
if (!String.IsNullOrEmpty (attr))76
throw new ProviderException77
("Unrecognized attribute: " + attr);78
}79
}80

81
public override Image RetrieveImage (string id)82
{83
// TODO: Retrieve an image from the database using84
// _connectionString to open a database connection85
}86

87
public override void SaveImage (string id, Image image)88
{89
throw new NotSupportedException ();90
}91
}
配置基于Provider的自定义服务
现在可以看看如何在 Web.Config 中配置它所需的节点。这里在 <System.Web> 节中添加了 <ImageService> 节,在属性 defaultProvider 中指定了它使用的默认 Provider 服务。
3. Web.Config 文件中配置 Image Service
<configuration >2

3
<connectionStrings>4
<add name="ImageServiceConnectionString" connectionString="
" />5
</connectionStrings>6
<system.web>7
<imageService defaultProvider="SqlImageProvider">8
<providers>9
<add name="SqlImageProvider" type="SqlImageProvider"10
connectionStringName="ImageServiceConnectionString"/>11
</providers>12
</imageService>13
</system.web>14
</configuration>
结构节点<ImageServer> 现在系统是不可识别的,所有必需还要有一个相应的类用来描述 <ImageServer> 配置节。
4. <imageServer> 配置节的描述类
using System;2
using System.Configuration;3

4
public class ImageServiceSection : ConfigurationSection5
{6
[ConfigurationProperty("providers")]7
public ProviderSettingsCollection Providers8
{9
get { return (ProviderSettingsCollection) base["providers"]; }10
}11

12
[StringValidator(MinLength = 1)]13
[ConfigurationProperty("defaultProvider",14
DefaultValue = "SqlImageProvider")]15
public string DefaultProvider16
{17
get { return (string) base["defaultProvider"]; }18
set { base["defaultProvider"] = value; }19
}20
}21

22

这一下可以在 Web.Config 中注册 <imageService> 节了,并且它会被系统识别。
5. 创建 <imageService> 这个配置节的处理类
<configuration >2
<configSections>3
<sectionGroup name="system.web">4
<section name="imageService"5
type="ImageServiceSection, CustomSections"6
allowDefinition="MachineToApplication"7
restartOnExternalChanges="true" />8
</sectionGroup>9
</configSections>10
<connectionStrings>11
<add name="ImageServiceConnectionString" connectionString="
" />12
</connectionStrings>13
<system.web>14
<imageService defaultProvider="SqlImageProvider">15
<providers>16
<add name="SqlImageProvider" type="SqlImageProvider"17
connectionStringName="ImageServiceConnectionString"/>18
</providers>19
</imageService>20
</system.web>21
</configuration>22

23

现在可以加载并初始化自定义的 Providers
上面的事情都完成后,就可以实现这个 ImageService 了,它将根据 Web.Config 加载配置中默认的ImageProvider ,可以在 ImageService 类中直接使用它。
6、创建 ImageService 类,它将使用配置中的实例来处理
using System;2
using System.Drawing;3
using System.Configuration;4
using System.Configuration.Provider;5
using System.Web.Configuration;6
using System.Web;7

8
public class ImageService9
{10
private static ImageProvider _provider = null;11
private static ImageProviderCollection _providers = null;12
private static object _lock = new object();13
14
public ImageProvider Provider15
{16
get { return _provider; }17
}18

19
public ImageProviderCollection Providers20
{21
get { return _providers; }22
}23

24
public static Image RetrieveImage(int imageID)25
{26
// Make sure a provider is loaded27
LoadProviders();28

29
// Delegate to the provider30
return _provider.RetrieveImage(imageID);31
}32

33
public static void SaveImage(Image image)34
{35
// Make sure a provider is loaded36
LoadProviders();37

38
// Delegate to the provider39
_provider.SaveImage(image);40
}41

42
private static void LoadProviders()43
{44
// Avoid claiming lock if providers are already loaded45
if (_provider == null)46
{47
lock (_lock)48
{49
// Do this again to make sure _provider is still null50
if (_provider == null)51
{52
// Get a reference to the <imageService> section53
ImageServiceSection section = (ImageServiceSection)54
WebConfigurationManager.GetSection55
("system.web/imageService");56

57
// Load registered providers and point _provider58
// to the default provider59
_providers = new ImageProviderCollection();60
ProvidersHelper.InstantiateProviders61
(section.Providers, _providers,62
typeof(ImageProvider));63
_provider = _providers[section.DefaultProvider];64

65
if (_provider == null)66
throw new ProviderException67
("Unable to load default ImageProvider");68
}69
}70
}71
}72
}73

74

这些在 Asp.NET 2.0 中被支持。


浙公网安备 33010602011771号