娃娃爱喝娃哈哈 發表於 2013-10-28 21:47:00

从Microsoft.AspNet.Identity看微软推荐的一种MVC的分层架构

<style type="text/css">.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }
.csharpcode pre { margin: 0 }
.csharpcode .rem { color: rgba(0, 128, 0, 1) }
.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }
.csharpcode .str { color: rgba(0, 96, 128, 1) }
.csharpcode .op { color: rgba(0, 0, 192, 1) }
.csharpcode .preproc { color: rgba(204, 102, 51, 1) }
.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }
.csharpcode .html { color: rgba(128, 0, 0, 1) }
.csharpcode .attr { color: rgba(255, 0, 0, 1) }
.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }
.csharpcode .lnum { color: rgba(96, 96, 96, 1) }</style><h2>Microsoft.AspNet.Identity简介</h2> <p>Microsoft.AspNet.Identity是微软在MVC 5.0中新引入的一种membership框架,和之前ASP.NET传统的membership以及WebPage所带来的SimpleMembership(在MVC 4中使用)都有所不同。</p> <p>Microsoft.AspNet.Identity是符合微软开放Owin标准里面Security标准的一种实现。且在MVC 5中默认使用EntityFramework作为Microsoft.AspNet.Identity的数据存储实现。</p> <p>从Microsoft.AspNet.Identity里面,我们其实可以看出微软所采用的一种MVC的分层架构;或许这种分层架构我们可以学习并应用在自己的开发当中。</p> <p>Microsoft.AspNet.Identity从Preview到RC到RTM一直都有变化,下面我当然以RTM的结构来简单讲解一下这种值得借鉴的参考分层架构。</p> <h2>参考分层架构</h2> <p>首先要说明的是,我上面提到的分层架构不是指MVC本身的分层,而是指Controller与Data之间的分层(与耦合方式)。</p> <p>你在VS2013中创建一个带有独立账号管理的MVC项目后,默认就有一个用于登录、注册的AccountController,通过这个Controller,我们就可以顺藤摸瓜一窥Microsoft.AspNet.Identity的真容。</p> <p>我们先来看一个类图:</p> <p><img src="https://images.cnblogs.com/cnblogs_com/redmoon/527952/o_ClassDiagram1.png"></p> <p>从上图中,我们可以看到如下类以及他们的关系:</p> <p><strong>AccountController</strong></p> <p>账号管理的Controller。具有一个名为UserManager的属性,这个属性的类型为UserManager&lt;TUser&gt;。并暴露一个名为AuthenticationManager的属性,类型为IAuthenticationManager。</p> <p>Controller顾名思义只起到控制器的作用,就是把M和V结合在一起,而如何得到M如何处理M得到什么样的M,就是业务逻辑的事情。</p> <p>业务逻辑你可以很dirty的写中Controller里面,也可以像Microsoft.AspNet.Identity一样把用户管理的业务逻辑都封装到UserManager中。</p> <p>把登录和注销逻辑保证到AuthenticationManager中,当然AuthenticationManager实际上是一个来自于Owin的接口IAuthenticationManager,通过这样的设定,Microsoft.AspNet.Identity就和Owin的Security兼容了。不过我这里不会详细讲Owin的Security的。</p> <p>AccountController提供了两个构造方法:</p> <ol> <li>一个默认的:<pre class="csharpcode"> <span class="kwrd">public</span> AccountController()
            : <span class="kwrd">this</span>(<span class="kwrd">new</span> UserManager&lt;ApplicationUser&gt;(<span class="kwrd">new</span> UserStore&lt;ApplicationUser&gt;(<span class="kwrd">new</span> ApplicationDbContext())))
      {
      }</pre>
</li><li>一个可以传入UserManager实例的:<pre class="csharpcode"><span class="kwrd">public</span> AccountController(UserManager&lt;ApplicationUser&gt; userManager)
      {
            UserManager = userManager;
      }</pre></li></ol>
<p><strong>UserManager&lt;TUser&gt;(Microsoft.AspNet.Identity,Microsoft.AspNet.Identity.Core.dll)</strong></p>
<p>这些一个泛型的用户管理业务逻辑的类。泛型的原因是因为要支持Profile信息的扩展,这里也不详细介绍。UserManager&lt;TUser&gt;仅仅是封装了业务处理的逻辑,并没有去实现数据如何处理的代码。相关代码都交给IUserStore&lt;TUser&gt;。</p>
<p>UserManager&lt;TUser&gt;只提供了一个接受IUserStore&lt;TUser&gt;实例的构造函数:</p><pre class="csharpcode"><span class="kwrd">public</span> UserManager(IUserStore&lt;TUser&gt; store);</pre>
<p><strong>IUserStore&lt;TUser&gt;(Microsoft.AspNet.Identity,Microsoft.AspNet.Identity.Core.dll)</strong></p>
<p>这个接口抽象了用户数据如何处理的逻辑。但是具体实现要交给和具体数据访问技术相关的实现。从AccountController的默认构造函数中,我们可以看到给UserManager传入了一个IUserStore&lt;TUser&gt;的实现UserStore&lt;ApplicationUser&gt;。</p>
<p><strong>UserStore&lt;TUser&gt;(Microsoft.AspNet.Identity.EntityFramework,Microsoft.AspNet.Identity.EntityFramework.dll)</strong></p>
<p>这个类实现IUserStore&lt;TUser&gt;接口以及一系列相关接口(比如:IUserLoginStore&lt;TUser&gt;等)。这个类实际上为UserManager提供了对用户真实数据的访问能力,在这里,是把用户数据通过EntityFramework来存储和获取的(而数据实际是保存中SQL Server的各类版本中还是保存在MySQL中,就又取决于EntityFramework的数据库驱动适配层了,和这个分层架构实际上无关了)。而由于UserStore&lt;TUser&gt;是依赖于EntityFramework来存取数据的,所以他的构造函数也接受DbContext作为参数:</p><pre class="csharpcode"><span class="kwrd">public</span> UserStore(DbContext context);</pre>
<p>虽然DbContext是一个通用的类,不过从AccountController的构造函数中,我们还是可以看到实际上传入的是一个继承于IdentityDbContext&lt;TUser&gt;的DbContext。</p>
<p><strong>IdentityDbContext&lt;TUser&gt;(Microsoft.AspNet.Identity.EntityFramework,Microsoft.AspNet.Identity.EntityFramework.dll)</strong></p>
<p>这是一个包含了Code-First模型定义的DbContext了,其中当然定义了Users这个IDbSet&lt;TUser&gt;,所以对用户数据的操作最终都是由这个DbContext完成的。</p>
<h2>类似架构的讲解</h2>
<p>这里的这篇文章(http://www.codeproject.com/Articles/207820/The-Repository-Pattern-with-EF-code-first-Dependen)其实就讲解了这种类似的分层架构。</p>
<p>其中,文章中提到的IRepository(特定于某个领域类的ICategoryRepository)就是IUserStore,而CategoryRepository就类似于UserStore&lt;TUser&gt;,而CatalogService和UserManager比较接近。</p>
<h2>通过依赖注入充分利用这种架构的灵活性</h2>
<p>从上面的这些类的构造函数中,我们还可以看到以各种重要特点,就是好几个类都具有参数构造函数,这样的设计不得不说是为了依赖注入而准备了。所以,我也简单讲解一下如何用Unity来进行简单的依赖注入(其他依赖注入框架用法类似)。</p>
<p>首先,通过NuGet来添加Unity和Unity.Mvc这两个包。</p>
<p>添加以后,在App_Start文件夹里面会出现两个文件:UnityConfig.cs和UnityMvcActivator.cs,在UnityConfig.cs文件中的RegisterTypes函数中,添加如下两行代码:</p><pre class="csharpcode">            container.RegisterType&lt;IUserStore&lt;ApplicationUser&gt;, UserStore&lt;ApplicationUser&gt;&gt;();
            container.RegisterType&lt;DbContext, ApplicationDbContext&gt;();</pre>
<p>就可以非常简单地利用Unity来把相关实现类注入进去。所以在这里,你可以把自己实现的UserStore注入进去,假设你的UserStore用到的是类似MongoDB这样的NoSQL的话,那么你同样也可以把MongoDB的session注入进去。</p>
<p>通过定义接口,基于接口实现,并在相关类上暴露具有参数的构造函数,可以实现各个分层实现之间的松耦合,并通过依赖注入来极大的增加代码的灵活性。</p>
<h2>总结</h2>
<p>在我们的实际项目开发中,如果为了获得灵活性完全可以照搬这种模式;当然,如果只是想快速实现一个原型或者就是一个小项目的话,那么在Controller里面直接调用DbContext也没有什么大不了的。</p>
<p><strong>update-2013-11-04 </strong>关于ASP.NET Identity的更多信息,可以参考官方文档:http://www.asp.net/identity/overview/getting-started</p>

</div>
<div id="MySignature" role="contentinfo">
    <!-- JiaThis Button BEGIN -->
<div class="jiathis_style">
        <span class="jiathis_txt">分享到:</span>
       
       
       
       
        更多
       
</div>


<!-- JiaThis Button END --><br><br>
来源:https://www.cnblogs.com/redmoon/p/3393264.html
頁: [1]
查看完整版本: 从Microsoft.AspNet.Identity看微软推荐的一种MVC的分层架构