设为首页 - 加入收藏 焦点技术网
热搜:java
当前位置:首页 >

【ASP.NET】ASP.NET MVC 3 & Unity.MVC3

导读:最近学习了下 ASP.NET MVC,比较之前的 WebForm 没有了 IsPostBack 的判断,事件处理也被 Action 取代。MVC 中 WebForm中大量的事件处理中UI绑定,混杂的 js 注入, style 修改没有了;服务端控件不用了,结局是 View 被释放了,Controller可以被单元测试了,拿着 ViewModel 可以快速替换 View。(说句实话要不是有 Razo...。。。
最近学习了下 ASP.NET MVC,比较之前的 WebForm 没有了 IsPostBack 的判断,事件处理也被 Action 取代。MVC 中 WebForm中大量的事件处理中UI绑定,混杂的 js 注入, style 修改没有了;服务端控件不用了,结局是 View 被释放了,Controller可以被单元测试了,拿着 ViewModel 可以快速替换 View。(说句实话要不是有 Razor 这样的页面引擎加上 VS IDE 的强力智能感知,ASP.NET MVC 和 JSP 没有区别,说不定还会有人把 strust 标签,spring 标签拿来在 .NET 上封装一遍)

再加上现在的 EF,Model层以及DAL实现很自然的交给了 EF等ORM框架。加上现在的成熟的 Repository Pattern 和 UnitOfWork Pattern 实践上的Service分层也变成约定俗成。(关于 Repository 和 UnitOfWork 参看:Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application) 。分离出 Repository, UnitOfWork  就是避免在 Controller 里直接写入 Linq2Db 的代码,这样难以实现 Mockup,好比下面的代码:

(详细参考:Walkthrough: Using TDD with ASP.NET MVC

【没有使用 Repository Pattern 的代码】

public class HomeController : Controller {    ContactEntities _db = new ContactEntities();    public ActionResult Index() {        var dn = _db.Contacts;        return View(dn);    }}

【使用 Repository Pattern 的代码】

namespace MvcContacts.Models {    public class EF_ContactRepository : MvcContacts.Models.IContactRepository {        private ContactEntities _db = new ContactEntities();        public Contact GetContactByID(int id) {            return _db.Contacts.FirstOrDefault(d => d.Id == id);        }...
测试可以用个 Mock Repository,_db 数据从哪来就自由了...
namespace MvcContacts.Tests.Models {    class InMemoryContactRepository : MvcContacts.Models.IContactRepository {        private List _db = new List();...
而 Controller 变成这样:
public class HomeController : Controller {        IContactRepository _repository;        public HomeController() : this(new EF_ContactRepository()) { }        public HomeController(IContactRepository repository) {            _repository = repository;        }        public ViewResult Index() {            throw new NotImplementedException();        }    }}


其实上面的都是引子,用 Unity 目的是进一步推迟 Repository 或者 UnitOfWork (很多时候演变成 Service 了) 的实例化时机,交给了 IoC 容器注入。以达到更灵活切换的目的,比如从 MS Entities 变换到 MySql Entities 或者是从 ObjectContext  变换到  DbContext (CodeFirst)。

下面介绍一下 Unity.MVC3 的实践过程:
1.  EF CodeFirst Models
用 EF CodeFirst 创建一个 Models 工程,用来管理 Entities 

表很简单,只有一个 DbSet 

namespace MvcWithUnityTest.Models{    public class DbEntities : DbContext    {        public DbSet Users { get; set; }    }}

2. GenericRepository 
主要针对 EF(ObjectContext) 和 EF CodeFirst(DbContext) 抽出接口 IRepository

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Linq.Expressions;namespace GenericRepository{    public interface IRepository : IDisposable where T : class    {        IQueryable AsQueryable();        IEnumerable GetAll();        IEnumerable Find(Expression> where);        T Single(Expression> where);        T First(Expression> where);        void Delete(T entity);        void Add(T entity);        void Update(T entity);    }}
DbContextRepository 对应于 DbContext 的 IRepository 实现,通过构造方法注入 Context  实例
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data.Entity;using System.Linq.Expressions;namespace GenericRepository{    public class DbContextRepository : IRepository where T : class    {        protected DbSet _objectSet;        protected DbContext _context;        public DbContextRepository(DbContext context)        {            _objectSet = context.Set();            _context = context;        }        public IQueryable AsQueryable()        {            return _objectSet;        }        public IEnumerable GetAll()        {            return _objectSet.ToList();        }        public IEnumerable Find(Expression> where)        {            return _objectSet.Where(where);        }        public T Single(Expression> where)        {            return _objectSet.Single(where);        }        public T First(Expression> where)        {            return _objectSet.First(where);        }        public void Delete(T entity)        {            if (_context.Entry(entity).State == System.Data.EntityState.Detached)                _objectSet.Attach(entity);            _objectSet.Remove(entity);        }        public void Add(T entity)        {            _objectSet.Add(entity);        }        public void Update(T entity)        {            _objectSet.Attach(entity);            _context.Entry(entity).State = System.Data.EntityState.Modified;        }        public void Dispose()        {            System.Diagnostics.Trace.WriteLine("context dispose");            _context.Dispose();        }    }}

3. MVC Web 应用
(1)  先通过 NuGet 获取 Unity.MVC3 

ASP.NET MVC3 中开放了依赖注入容器的接口 IDependencyResolver,ASP.NET Controller 被调用时,会利用该接口进行依赖注入。因此可以利用这个接口,
使用任何的依赖注入容器。另外,Unity.MVC3.dll 在 UnityContainerExtensions 类里扩展了 RegisterControllers 方法,
 它将为当前 Assembly 所有非 abstract Controller 完成注册(来自 IControllerFactory 的依赖 ) 


添加完毕,会发现在 Web 工程下多出 Bootstrapper.cs 文件


public static class Bootstrapper{    public static void Initialise()    {        var container = BuildUnityContainer();        DependencyResolver.SetResolver(new UnityDependencyResolver(container));    }    private static IUnityContainer BuildUnityContainer()    {        var container = new UnityContainer();        // register all your components with the container here        // e.g. container.RegisterType();                container.LoadConfiguration("default");        container.RegisterControllers();        return container;    }}

这里我把依赖关系都放到配置文件里了:

      
...
然后在 Global.asax.cs 里调用  Bootstrapper.Initialise(); 即可。

另外,需要注意的是  里加上了  
这样在 Controller 生命周期结束时才会调用 Dispose。(待展开)


再来看看 Controller 的实现:

根据上面的配置文件:DbContextRepository[User]"> 
[Dependency] 标识的 UserRepository 会在 Controller 请求时被注入实例。

public class HomeController : Controller {     [Dependency]     public IRepository UserRepository { get; set; }     public ActionResult Index()     {         ViewBag.Message = "ASP.NET MVC3 With Unity.MVC3!";         var users = UserRepository.GetAll();         return View(users);     }     public ActionResult About()     {         return View();     } }
运行:



利用了 IoC 整个系统结构,好比如下图:




(编辑: fangxinggood)

网友评论
相关文章