zoukankan      html  css  js  c++  java
  • BlogEngine.Net架构与源代码分析系列part3:数据存储——基于Provider模式的实现

    上一篇文章中,我们主要分析了一下BlogEngine.Net的整体设计,在后半部分我们又对BusinessBase业务对象的状态维护做了一些比较深入的探讨。在这篇文章中我将引领大家完成对BlogEngine.Net中业务对象数据存储的设计思路与实现细节的分析。

    BlogEngine.Net中的数据存储主要是应用Provider模式实现的,那么首先让我们认识一下Provider模式。

        Provider模式应该是一种设计模式,是用来解决软件变化问题的。不过它关注的角度(或者维度)是功能声明跟功能实现的分离。一般来说,系统对某一功能的需求可能是相对稳定的(比如每个系统都要求对登录用户进行验证,这个需要是相对稳定的),而这个功能的的具体实现却可以是多样的(比如,你可以去数据库里匹配用户进行验证,也可以去一个XML文件里面去匹配)。Provider模式在.Net类库的设计中随处可见,如:MembershipProvider、SiteMapProvider等,它的出现使我们的应用程序有了更大的扩展性,要注意Provider可以是一个数据工厂的提供者,也可以是一个逻辑处理的提供者。在BlogEngine.Net中我们看到的都是数据工厂的提供者,对于逻辑处理的提供者,大家可以参考一下微软企业库ApplicationBlock中的加密Block的实现。
        在.Net中要实现这种模式是相当的简单,因为它已经为我们实现了一部分,我们只需实现以下三步即可:
    1、定义一个类,抽象出我们所需要的操作,它的基类为ProviderBase
    2、实现一个Section,用来从配置文件中读取Provider的相关配置,该类继承于ConfigurationSection
    3、在调用时去读取配置文件,并加载指定的Provider

    对于BlogEngine.Net中的数据存储部分我是怎么看的呢(个人观点,不必在意)?

        BlogEngine.Net可以支持多种数据存储,在它目前的版本中我们可以看到XML(默认采用,主要是为安装时即插即用考虑的)和数据库两种存储方式。BlogEngine.Net数据存储的Provider只是针对数据如何存储部分(不涉及到一些逻辑处理与运算),所以对于数据库的要求非常的低,只要支持SQL语句并可以存储数据就行,实际上它在数据库中只有一些表,从它的Provider的实现来看并没有使用数据库的主键级联删除等功能,而完全使用多条嵌入式SQL语句完成,这样做就可以使BlogEngine.Net支持更多的数据库。对于数据库的存储BlogEngine.Net只使用了一个DbBlogProvider,而没有具体区分到底采用何种数据库,我们只要在配置文件中根据链接字符串设定providerName就可以指定具体的数据库存储了。BlogEngine.Net的这种对数据处理方式在业务逻辑很复杂的系统中我并不是很推荐。

    那么再让我们看看在BlogEngine.Net中是怎样应用ProviderBase来完成数据存储问题的。

        先看一幅继承关系图:

    附件: Provider.jpg

    从上图我们可以看出DbBlogProvider和XmlBlogProvider都继承了抽象类BlogProvider(包含一些业务类或其它类等的操作声明),而BlogProvider直接继承自ProviderBase,ProviderBase是微软的标准Provider框架,我们只要按照这种模型开发就行了,这个标准的Provider框架已经解决很多问题,例如依赖注入问题等。为了利用.Net平台已有资源对于角色和成员BlogEngine.Net采用了.Net提供的MembershipProvider和RoleProvider,BlogEngine.Net中DbMembershipProvider,XmlMembershipProvider继承于MembershipProvider,DbRoleProvider和XmlRoleProvider继承于RoleProvider,.Net的MembershipProvider和RoleProvider同样也继承自ProviderBase。BlogProviderSection这个类是为了解决配置问题的,也就是.Net中Provider模式实现中的第二步,这就很好的解决了依赖注入问题。BlogProvider定义了一些业务类的标准的操作方法:

    1. 1 // Page
    2. 2 /// <summary>
    3. 3 /// Retrieves a Page from the provider based on the specified id.
    4. 4 /// </summary>
    5. 5 public abstract Page SelectPage(Guid id);
    6. 6 /// <summary>
    7. 7 /// Inserts a new Page into the data store specified by the provider.
    8. 8 /// </summary>
    9. 9 public abstract void InsertPage(Page page);
    10. 10 /// <summary>
    11. 11 /// Updates an existing Page in the data store specified by the provider.
    12. 12 /// </summary>
    13. 13 public abstract void UpdatePage(Page page);
    14. 14 /// <summary>
    15. 15 /// Deletes a Page from the data store specified by the provider.
    16. 16 /// </summary>
    17. 17 public abstract void DeletePage(Page page);
    18. 18 /// <summary>
    19. 19 /// Retrieves all Pages from the provider and returns them in a List.
    20. 20 /// </summary>
    21. 21 public abstract List<Page> FillPages();
    复制代码

    子类只要重写这些方法就可以了。

        此外在BlogEngine.Net中还有一个比较推荐的处理,由于BlogProvider需要处理很多业务类型数据的操作,方法成员就会很多,所以在实现XmlBlogProvider时采用了partial class解决。

        DbBlogProvider重写了ProviderBase的Initialize方法来达到链接字符串、表前缀、字段前缀等的获得,这么设计我觉得用处可能是由于BlogEngine.Net的数据库只有数据存储功能,用户可能直接把它部署到了已有数据库中,为了和已有数据库中的其它表区分,我们可以指定一个表名前缀。对于DbRoleProvider和DbMembershipProvider处理方式也是类似。在实现时BlogEngine.Net似乎也考虑了Mono,部分代码出现了对Mono运行时的判断,但是我没有试过是否可以跨平台安装,感兴趣的朋友可以研究一下!

    客户端是如何使用BlogProvider的呢?

        对于MembershipProvider和RoleProvider的使用这里不再介绍,可以参照一下MSDN文档,BlogEngine.Net也是这么用的。这里主要讲一下BlogProvider的使用问题,BlogEngine.Net中提供了一个BlogService的静态类,这个类提供给外界一个统一的数据访问接口,它内部的静态方法实现调用BlogProvider来完成。在BlogService中有一个LoadProviders方法来根据配置文件动态加载BlogProvider:

    BlogService

    1. 1Provider model#region Provider model
    2. 2
    3. 3private static BlogProvider _provider;
    4. 4private static BlogProviderCollection _providers;
    5. 5private static object _lock = new object();
    6. 6
    7. 7/**//// <summary>
    8. 8/// Gets the current provider.
    9. 9/// </summary>
    10. 10public static BlogProvider Provider
    11. 11{
    12. 12    get { LoadProviders(); return _provider; }
    13. 13}
    14. 14
    15. 15/**//// <summary>
    16. 16/// Gets a collection of all registered providers.
    17. 17/// </summary>
    18. 18public static BlogProviderCollection Providers
    19. 19{
    20. 20    get { LoadProviders(); return _providers; }
    21. 21}
    22. 22
    23. 23/**//// <summary>
    24. 24/// Load the providers from the web.config.
    25. 25/// </summary>
    26. 26private static void LoadProviders()
    27. 27{
    28. 28    // Avoid claiming lock if providers are already loaded
    29. 29    if (_provider == null)
    30. 30    {
    31. 31        lock (_lock)
    32. 32        {
    33. 33            // Do this again to make sure _provider is still null
    34. 34            if (_provider == null)
    35. 35            {
    36. 36                // Get a reference to the <blogProvider> section
    37. 37                BlogProviderSection section = (BlogProviderSection)WebConfigurationManager.GetSection("BlogEngine/blogProvider");
    38. 38
    39. 39                // Load registered providers and point _provider
    40. 40                // to the default provider
    41. 41                _providers = new BlogProviderCollection();
    42. 42                ProvidersHelper.InstantiateProviders(section.Providers, _providers, typeof(BlogProvider));
    43. 43                _provider = _providers[section.DefaultProvider];
    44. 44
    45. 45                if (_provider == null)
    46. 46                    throw new ProviderException("Unable to load default BlogProvider");
    47. 47            }
    48. 48        }
    49. 49    }
    50. 50}
    51. 51
    52. 52#endregion
    复制代码

    最后让我们看一下Web.config的相应配置

    BlogProviderConfig

    1. 1 <configSections>
    2. 2        <sectionGroup name="BlogEngine">
    3. 3            <section name="blogProvider" requirePermission="false" type="BlogEngine.Core.Providers.BlogProviderSection, BlogEngine.Core" allowDefinition="MachineToApplication" restartOnExternalChanges="true"/>
    4. 4        </sectionGroup>
    5. 5    </configSections>
    6. 6    <BlogEngine>
    7. 7        <blogProvider defaultProvider="XmlBlogProvider">
    8. 8            <providers>
    9. 9                <add name="XmlBlogProvider" type="BlogEngine.Core.Providers.XmlBlogProvider, BlogEngine.Core"/>
    10. 10                <add name="DbBlogProvider" type="BlogEngine.Core.Providers.DbBlogProvider, BlogEngine.Core" connectionStringName="BlogEngine" />
    11. 11            </providers>
    12. 12        </blogProvider>
    13. 13    </BlogEngine>
    复制代码

    MembershipProviderConfig和RoleProviderConfig

    1. 1 <membership defaultProvider="XmlMembershipProvider">
    2. 2            <providers>
    3. 3                <clear/>
    4. 4                <add name="XmlMembershipProvider" type="BlogEngine.Core.Providers.XmlMembershipProvider, BlogEngine.Core" description="XML membership provider" passwordFormat="Hashed"/>
    5. 5                <add name="SqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="BlogEngine" applicationName="BlogEngine"/>
    6. 6                <add name="DbMembershipProvider" type="BlogEngine.Core.Providers.DbMembershipProvider, BlogEngine.Core" passwordFormat="Hashed" connectionStringName="BlogEngine"/>
    7. 7            </providers>
    8. 8        </membership>
    9. 9       
    10. 10    <roleManager defaultProvider="XmlRoleProvider" enabled="true" cacheRolesInCookie="true" cookieName=".BLOGENGINEROLES">
    11. 11            <providers>
    12. 12                <clear/>
    13. 13                <add name="XmlRoleProvider" type="BlogEngine.Core.Providers.XmlRoleProvider, BlogEngine.Core" description="XML role provider"/>
    14. 14                <add name="SqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="BlogEngine" applicationName="BlogEngine"/>
    15. 15                <add name="DbRoleProvider" type="BlogEngine.Core.Providers.DbRoleProvider, BlogEngine.Core" connectionStringName="BlogEngine"/>
    16. 16            </providers>
    17. 17        </roleManager>
    复制代码

    总结

        BlogEngine.Net数据存储的实现应用了Provider模式,这个在.Net平台下有很好的支持和案例,这种设计思想很值得借鉴,尤其是BlogService设计的很巧妙,也有一点面向服务的味道。不过在一些业务逻辑非常复杂,尤其是一些应用到数据库逻辑处理的系统设计时,这种设计可能就无法满足需求了,还要坚持数据的处理离数据越近越好的原则。

        取其精华!

  • 相关阅读:
    [设计模式]在CodeDom代码生成中使用Decorator模式实现类型创建
    【翻译】防腐层:面向领域驱动设计的更为稳健的系统集成方案
    EntityFramework之领域驱动设计实践【后续篇】:基于EF 4.3.1 Code First的领域驱动设计实践案例
    Apworks框架中各种仓储实现的性能基准测试与结果对比
    CQRS架构中同步服务的一种实现方式
    在Visual Studio 2010中创建多项目(解决方案)模板【三】
    Microsoft NLayerApp案例理论与实践 应用层
    在Visual Studio 2010中创建多项目(解决方案)模板【二】
    小猫奥斯卡
    测试一下又拍网图片外链
  • 原文地址:https://www.cnblogs.com/encounter/p/2188815.html
Copyright © 2011-2022 走看看