基于Provider的自定义服务
【IT168技术文档】
在使用 Membership 的时候可以为同一种操作方法定义多种行为,而具体使用哪种行为只需要在 Web.Config 中定义即可。
这样可以极大的促进了系统的灵活性,可是 Membership 这种 Provider 服务是怎么设计的呢?查了一些资料,也查看了 .Framework 2.0 的反编译源码,最终还是在 MSDN 上的一篇英文资料中找到了答案。
设计这种模式,似乎并不是那么容易,需要设计许多类方可构建基于Provider的自定义服务。
下面是一个基本Provider的自定义服务的示例,它公开了两个操作方法“RetrieveImage”和“SaveImage”。它有可以会使用不同的数据库,这样可以定义多种处理方法。只需要在 Web.Config 中进行配置,就可以让系统调用相应的行为来进行处理。
1、 首先构建一个 ImageProvider 它继承了 ProviderBase 类。
2、 我们先定义一个使用 SQL Server 的处理方法。ProviderBase#region 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);
}
}
#endregion
配置基于Provider的自定义服务,现在可以看看如何在 Web.Config 中配置它所需的节点。这里在 <System.Web> 节中添加了 <ImageService> 节,在属性 defaultProvider 中指定了它使用的默认 Provider 服务。SqlServer 处理方法#region SqlServer 处理方法
[SqlClientPermission (SecurityAction.Demand, Unrestricted=true)]
public class SqlImageProvider : ImageProvider
...{
private string _applicationName;
private string _connectionString;
![]()
public override string ApplicationName
...{
get ...{ return _applicationName; }
set ...{ _applicationName = value; }
}
![]()
public override bool CanSaveImages
...{
get ...{ return false; }
}
![]()
public string ConnectionStringName
...{
get ...{ return _connectionStringName; }
set ...{ _connectionStringName = value; }
}
![]()
public override void Initialize (string name,
NameValueCollection config)
...{
// Verify that config isn't null
if (config == null)
throw new ArgumentNullException ("config");
![]()
// Assign the provider a default name if it doesn't have one
if (String.IsNullOrEmpty (name))
name = "SqlImageProvider";
![]()
// Add a default "description" attribute to config if the
// attribute doesn't exist or is empty
if (string.IsNullOrEmpty (config["description"])) ...{
config.Remove ("description");
config.Add ("description",
"SQL image provider");
}
![]()
// Call the base class's Initialize method
base.Initialize(name, config);
![]()
// Initialize _applicationName
_applicationName = config["applicationName"];
![]()
if (string.IsNullOrEmpty(_applicationName))
_applicationName = "/";
![]()
config.Remove["applicationName"];
![]()
// Initialize _connectionString
string connect = config["connectionStringName"];
![]()
if (String.IsNullOrEmpty (connect))
throw new ProviderException
("Empty or missing connectionStringName");
![]()
config.Remove ("connectionStringName");
![]()
if (WebConfigurationManager.ConnectionStrings[connect] == null)
throw new ProviderException ("Missing connection string");
![]()
_connectionString = WebConfigurationManager.ConnectionStrings
[connect].ConnectionString;
![]()
if (String.IsNullOrEmpty (_connectionString))
throw new ProviderException ("Empty connection string");
![]()
// Throw an exception if unrecognized attributes remain
if (config.Count > 0) ...{
string attr = config.GetKey (0);
if (!String.IsNullOrEmpty (attr))
throw new ProviderException
("Unrecognized attribute: " + attr);
}
}
![]()
public override Image RetrieveImage (string id)
...{
// TODO: Retrieve an image from the database using
// _connectionString to open a database connection
}
public override void SaveImage (string id, Image image)
...{
throw new NotSupportedException ();
}
}
#endregion
3. Web.Config 文件中配置 Image Service
结构节点<ImageServer> 现在系统是不可识别的,所有必需还要有一个相应的类用来描述 <ImageServer> 配置节。<configuration >
<connectionStrings>
<add name="ImageServiceConnectionString" connectionString="" />
</connectionStrings>
<system.web>
<imageService defaultProvider="SqlImageProvider">
<providers>
<add name="SqlImageProvider" type="SqlImageProvider"
connectionStringName="ImageServiceConnectionString"/>
</providers>
</imageService>
</system.web>
</configuration>
4. <imageServer> 配置节的描述类
这一下可以在 Web.Config 中注册 <imageService> 节了,并且它会被系统识别。描述类#region 描述类
using System;
using System.Configuration;
![]()
public class ImageServiceSection : ConfigurationSection
...{
[ConfigurationProperty("providers")]
public ProviderSettingsCollection Providers
...{
get ...{ return (ProviderSettingsCollection) base["providers"]; }
}
![]()
[StringValidator(MinLength = 1)]
[ConfigurationProperty("defaultProvider",
DefaultValue = "SqlImageProvider")]
public string DefaultProvider
...{
get ...{ return (string) base["defaultProvider"]; }
set ...{ base["defaultProvider"] = value; }
}
}
#endregion
5. 创建 <imageService> 这个配置节的处理类
现在可以加载并初始化自定义的 Providers 上面的事情都完成后,就可以实现这个 ImageService 了,它将根据 Web.Config 加载配置中默认的ImageProvider ,可以在 ImageService 类中直接使用它。<configuration >
<configSections>
<sectionGroup name="system.web">
<section name="imageService"
type="ImageServiceSection, CustomSections"
allowDefinition="MachineToApplication"
restartOnExternalChanges="true" />
</sectionGroup>
</configSections>
<connectionStrings>
<add name="ImageServiceConnectionString" connectionString="" />
</connectionStrings>
<system.web>
<imageService defaultProvider="SqlImageProvider">
<providers>
<add name="SqlImageProvider" type="SqlImageProvider"
connectionStringName="ImageServiceConnectionString"/>
</providers>
</imageService>
</system.web>
</configuration>
6、创建 ImageService 类,它将使用配置中的实例来处理
这些在 Asp.NET 2.0 中被支持。ImageService类#region ImageService类
using System;
using System.Drawing;
using System.Configuration;
using System.Configuration.Provider;
using System.Web.Configuration;
using System.Web;
![]()
public class ImageService
...{
private static ImageProvider _provider = null;
private static ImageProviderCollection _providers = null;
private static object _lock = new object();
![]()
public ImageProvider Provider
...{
get ...{ return _provider; }
}
![]()
public ImageProviderCollection Providers
...{
get ...{ return _providers; }
}
![]()
public static Image RetrieveImage(int imageID)
...{
// Make sure a provider is loaded
LoadProviders();
![]()
// Delegate to the provider
return _provider.RetrieveImage(imageID);
}
![]()
public static void SaveImage(Image image)
...{
// Make sure a provider is loaded
LoadProviders();
![]()
// Delegate to the provider
_provider.SaveImage(image);
}
![]()
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 <imageService> section
ImageServiceSection section = (ImageServiceSection)
WebConfigurationManager.GetSection
("system.web/imageService");
![]()
// Load registered providers and point _provider
// to the default provider
_providers = new ImageProviderCollection();
ProvidersHelper.InstantiateProviders
(section.Providers, _providers,
typeof(ImageProvider));
_provider = _providers[section.DefaultProvider];
![]()
if (_provider == null)
throw new ProviderException
("Unable to load default ImageProvider");
}
}
}
}
}
#endregion
0
相关文章
