分享

基于Provider的自定义服务 - MaxFree's Tech Space - 博客...

 miky 2008-05-29

基于Provider的自定义服务

在使用 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 getset; }
    
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 的处理方法。

 

 1[SqlClientPermission (SecurityAction.Demand, Unrestricted=true)]
 2public class SqlImageProvider : ImageProvider
 3{
 4    private string _applicationName;
 5    private string _connectionString;
 6
 7    public override string ApplicationName
 8    {
 9        get return _applicationName; }
10        set { _applicationName = value; }
11    }

12
13    public override bool CanSaveImages
14    {
15        get return false; }
16    }

17
18    public string ConnectionStringName
19    {
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 null
28        if (config == null)
29            throw new ArgumentNullException ("config");
30
31        // Assign the provider a default name if it doesn't have one
32        if (String.IsNullOrEmpty (name))
33            name = "SqlImageProvider";
34
35        // Add a default "description" attribute to config if the
36        // attribute doesn't exist or is empty
37        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 method
44        base.Initialize(name, config);
45
46        // Initialize _applicationName
47        _applicationName = config["applicationName"];
48
49        if (string.IsNullOrEmpty(_applicationName))
50            _applicationName = "/";
51
52        config.Remove["applicationName"];
53
54        // Initialize _connectionString
55        string connect = config["connectionStringName"];
56
57        if (String.IsNullOrEmpty (connect))
58            throw new ProviderException
59                ("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.ConnectionStrings
67            [connect].ConnectionString;
68
69        if (String.IsNullOrEmpty (_connectionString))
70            throw new ProviderException ("Empty connection string");
71
72        // Throw an exception if unrecognized attributes remain
73        if (config.Count > 0{
74            string attr = config.GetKey (0);
75            if (!String.IsNullOrEmpty (attr))
76                throw new ProviderException
77                    ("Unrecognized attribute: " + attr);
78        }

79    }

80
81    public override Image RetrieveImage (string id)
82    {
83        // TODO: Retrieve an image from the database using
84        // _connectionString to open a database connection
85    }

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

 1<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> 配置节的描述类

 1using System;
 2using System.Configuration;
 3
 4public class ImageServiceSection : ConfigurationSection
 5{
 6    [ConfigurationProperty("providers")]
 7    public ProviderSettingsCollection Providers
 8    {
 9        get { return (ProviderSettingsCollection) base["providers"]; }
10    }
11
12    [StringValidator(MinLength = 1)]
13    [ConfigurationProperty("defaultProvider",
14        DefaultValue = "SqlImageProvider")]
15    public string DefaultProvider
16    {
17        get { return (string) base["defaultProvider"]; }
18        set { base["defaultProvider"] = value; }
19    }
20}
21
22

这一下可以在 Web.Config 中注册 <imageService> 节了,并且它会被系统识别。

5. 创建 <imageService> 这个配置节的处理类

 

 1<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 类,它将使用配置中的实例来处理

 

 1using System;
 2using System.Drawing;
 3using System.Configuration;
 4using System.Configuration.Provider;
 5using System.Web.Configuration;
 6using System.Web;
 7
 8public class ImageService
 9{
10    private static ImageProvider _provider = null;
11    private static ImageProviderCollection _providers = null;
12    private static object _lock = new object();
13    
14    public ImageProvider Provider
15    {
16        get return _provider; }
17    }

18
19    public ImageProviderCollection Providers
20    {
21        get return _providers; }
22    }

23
24    public static Image RetrieveImage(int imageID)
25    {
26        // Make sure a provider is loaded
27        LoadProviders();
28
29        // Delegate to the provider
30        return _provider.RetrieveImage(imageID);
31    }

32
33    public static void SaveImage(Image image)
34    {
35        // Make sure a provider is loaded
36        LoadProviders();
37
38        // Delegate to the provider
39        _provider.SaveImage(image);
40    }

41
42    private static void LoadProviders()
43    {
44        // Avoid claiming lock if providers are already loaded
45        if (_provider == null)
46        {
47            lock (_lock)
48            {
49                // Do this again to make sure _provider is still null
50                if (_provider == null)
51                {
52                    // Get a reference to the <imageService> section
53                    ImageServiceSection section = (ImageServiceSection)
54                        WebConfigurationManager.GetSection
55                        ("system.web/imageService");
56
57                    // Load registered providers and point _provider
58                    // to the default provider
59                    _providers = new ImageProviderCollection();
60                    ProvidersHelper.InstantiateProviders
61                        (section.Providers, _providers,
62                        typeof(ImageProvider));
63                    _provider = _providers[section.DefaultProvider];
64
65                    if (_provider == null)
66                        throw new ProviderException
67                            ("Unable to load default ImageProvider");
68                }

69            }

70        }

71    }

72}

73
74

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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多