`
sangei
  • 浏览: 336363 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

.net mvc 和 webapi中的IOC(Unity实现)

阅读更多

ASP.NETMVC3:正确实现UnityDependencyResolver

前日,dudu写了篇文章《想爱容易,相处难:当ASP.NETMVC爱上IoC》,介绍了在MVC中如何使用Unity,不过dudu犯了一个错误:错误地使用了Unity。这要先从Unity使用说起:Unity基本使用假定程序中有
 

前日,dudu 写了篇文章 《想爱容易,相处难:当ASP.NET MVC 爱上 IoC》,介绍了在 MVC 中如何使用 Unity,不过 dudu 犯了一个错误:错误地使用了 Unity。

这要先从 Unity 使用说起:

Unity 基本使用

假定程序中有如下两个接口:

1
2
public interface ICustomerRepository { /*...*/ }
public interface IOrderRepository { /*...*/ }

和两个实现类:

1
2
public class CustomerRepository : ICustomerRepository { /*...*/ }
public class OrderRepository : IOrderRepository { /*...*/ }

可以如下使用:

1
2
3
4
5
6
7
var container = new UnityContainer();
//注册
container.RegisterType<ICustomerRepository, CustomerRepository>();
container.RegisterType<IOrderRepository, OrderRepository>();
//使用
var customerRepository = container.Resolve<ICustomerRepository>();
var orderRepository = container.Resolve<IOrderRepository>();

(可在配置文件中注册,请参考相关文档)

但是实际使用中,情况要复杂的多,如下面这个接口和类(如何注入?):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface IOrderService { /*...*/ }

public class OrderService: IOrderService
{
    private ICustomerRepository customerRepository;
    private IOrderRepository orderRepository;

    public OrderService(ICustomerRepository customerRepository, IOrderRepository orderRepository) 
    {
        this.customerRepository = customerRepository;
        this.orderRepository = orderRepository;
    }
    /*...*/
}

有朋友会说,可以使用构造函数注入:

1
2
3
4
container.RegisterType<IOrderService, OrderService>(
    new InjectionConstructor(new CustomerRepository(), new OrderRepository())
    );
var orderService = container.Resolve<IOrderService>();

很好,这个这样可以解决这个问题。

但是,这种方式是存在一些缺陷的:

1、多次注册:我们已经将 CustomerRepository 注册给了 ICustomerRepository 接口,但在注册 IOrderService 接口时,还要 new CustomerRepository。多次注册会带来很多问题,假想有一天,我们需要将 CustomerRepository 统统换成 ImprovedCustomerRepository,使用这种方式不得不多处修改。

2、设计变动时,多处修改:设想 OrderService 的构造函数需要增加一个 IProductRepository 类型的参数,另外一个类 StoreService 的构造函数也要增加这么个参数。

3、更复杂的情况,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface IOrderController { /*...*/ }

public class OrderController: IOrderController
{
    private IOrderService orderService;
    private IStoreService storeService;

    public OrderController(IOrderService orderService, IStoreService storeService) 
    {
        this.orderService = orderService;
        this.storeService = storeService;
    }
}

如何在 Unity 中注册 IOrderController? 别告诉我用构造函数注入,这可得两级构造注入。

其实 Unity 支持 Circular References,可以轻松解决这些问题:

使用 Circular References

Circular References 翻译过来是“循环引用“。

Unity 中,不需要任何设置就可以使用 Circular References,使用一个例子来说明 :

1
2
3
4
5
6
7
var container = new UnityContainer();
container.RegisterType<ICustomerRepository, CustomerRepository>();
container.RegisterType<IOrderRepository, OrderRepository>();
container.RegisterType<IOrderService, OrderService>();
container.RegisterType<IOrderController, OrderController>();

var orderController = container.Resolve<IOrderController>();

说明(相当啰嗦,明白人可跳过):Unity 在获取 IOrderController 的实例时(第 7 行),根据第 5 行的注册得知,应该创建 OrderController 的实例。但 OrderController 有两个参数,类型分别是 IOrderService、IStoreService,势必先创建 IOrderService 的实例。根据第 4 行得知应该去创建 OrderService 的实例,OrderServer 又有 ICustomerRepository、IOrderRepository 两个参数,再根据第 2、3 行分别创建 CustomerRepository  和 OrderRepository 的实例,因为这两个类构造函数无参,直接可实例化。获取 IOrderService 实例化后,用类似的方式再获取 IStoreService 的实例。这样根据构造函数的参数,一步步向前,称为 Circular References Resolve。

有了 Circular References,不再需要过多的注册,Unity 会智能判断并处理。所以,即使一个类型没有注册在容器中,依然可以获取它的实例:

1
2
3
4
5
6
7
var container = new UnityContainer();
container.RegisterType<ICustomerRepository, CustomerRepository>();
container.RegisterType<IOrderRepository, OrderRepository>();
container.RegisterType<IOrderService, OrderService>();

bool isRegistered = container.IsRegistered<OrderController>(); //false
var controller = container.Resolve<OrderController>();

源码下载:UnityDemo.rar (522KB)

dudu 文中存在的问题

看了前面的部分,相信你一定能指出 dudu 文中 UnityDependencyResolver 存在问题,原代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class UnityDependencyResolver : IDependencyResolver
{
    IUnityContainer container;

    public UnityDependencyResolver(IUnityContainer container)
    {
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        if (!this.container.IsRegistered(serviceType))
        {
            return null;
        }
        return container.Resolve(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return container.ResolveAll(serviceType);
    }
}

没错,问题就在第 12~15 行,if (!this.container.IsRegistered(serviceType)) return null; 这句其实 ”屏蔽“ 了 Unity 的 Circular References,导致一系列问题,应该去除这四行代码。

另外,使用 Unity (或其它 DI 框架),不需要创建新的 ControllerFactory(如 dudu 文中的 UnityControllerFactory),除非有特殊需要。

从 ControllerBuilder 的源码中,可以看出,如果没有注册 IControllerFactory,MVC 将自动使用 DefaultControllerFactory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class ControllerBuilder {
    private Func<IControllerFactory> _factoryThunk = () => null;
    private static ControllerBuilder _instance = new ControllerBuilder();
    private IResolver<IControllerFactory> _serviceResolver;

    public ControllerBuilder() : this(null) { }

    internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver) {
        _serviceResolver = serviceResolver  new SingleServiceResolver<IControllerFactory>(
            () => _factoryThunk(),
             new DefaultControllerFactory { ControllerBuilder = this },
            "ControllerBuilder.GetControllerFactory"
        );
    }

    public static ControllerBuilder Current {
        get { return _instance; }
    }
    public IControllerFactory GetControllerFactory() {
        return _serviceResolver.Current;
    }
    public void SetControllerFactory(IControllerFactory controllerFactory) {
        if (controllerFactory == null)
            throw new ArgumentNullException("controllerFactory");
        _factoryThunk = () => controllerFactory;
    }
    //...
}

DefaultControllerFactory 在内部(DefaultControllerActivator 类)会尝试调用 DependencyResolver 来获取 Controller 的实例,如果不成功则使用 Activator.CreateInstance :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class DefaultControllerFactory : IControllerFactory {
    private IResolver<IControllerActivator> _activatorResolver;
    private IControllerActivator _controllerActivator;

    public DefaultControllerFactory() : this(null, null, null) { }
    public DefaultControllerFactory(IControllerActivator controllerActivator)
        : this(controllerActivator, null, null) { }

    internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver) {
        if (controllerActivator != null)
            _controllerActivator = controllerActivator;
        else
            _activatorResolver = activatorResolver  new SingleServiceResolver<IControllerActivator>(
                () => null,
                new DefaultControllerActivator(dependencyResolver),
                "DefaultControllerFactory contstructor"
            );
    }
    private class DefaultControllerActivator : IControllerActivator {
        Func<IDependencyResolver> _resolverThunk;

        public DefaultControllerActivator() : this(null) { }
        public DefaultControllerActivator(IDependencyResolver resolver) {
            if (resolver == null)
                _resolverThunk = () => DependencyResolver.Current;
            else
                _resolverThunk = () => resolver;
        }
        //...
        public IController Create(RequestContext requestContext, Type controllerType) {
            try {
                return (IController)(_resolverThunk().GetService(controllerType)  Activator.CreateInstance(controllerType));
            }
            catch (Exception ex) {
                //...
            }
        }
    }
}

通过前面的说明和分析,可以写出 UnityDependencyResolver 的参考实现:

UnityDependencyResolver 参考实现及使用

参考代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class UnityDependencyResolver : IDependencyResolver {

    private IUnityContainer container;

    public UnityDependencyResolver(IUnityContainer container) {
        this.container = container;
    }

    public object GetService(Type serviceType) {
        try {
            return container.Resolve(serviceType);
        }
        catch (ResolutionFailedException) {
            //额外操作,如日志
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType) {
        try {
            return container.ResolveAll(serviceType);
        }
        catch (ResolutionFailedException) {
            //额外操作,如日志
            return Enumerable.Empty<object>();
        }
    }
}

第 19~26 行 GetServices 好像还是有些问题的,有谁能指出吗? (答案在此:《ASP.NET MVC 3:放弃 Unity》)

建议实现 IViewPageActivator 接口并注册:

1
2
3
4
5
6
7
public class ViewPageActivator : IViewPageActivator
{
    public object Create(ControllerContext controllerContext, Type type)
    {
        return Activator.CreateInstance(type);
    }
}

在 Global.asax 文件中,注册如下:

1
2
3
4
5
6
7
8
9
protected void Application_Start()
{
    //...
    IUnityContainer container = new UnityContainer();
    container.RegisterType<IServiceA, ServiceA>();
    container.RegisterType<IServiceB, ServiceB>();;
    container.RegisterType<IViewPageActivator, ViewPageActivator>();
    DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}

不用担心 UnityDependencyResolver 异常处理带来的效率问题,因为就目前代码,启动之后 UnityDependencyResolver 中只会发生两次异常:获取 IControllerFactory 和 IControllerActivator 时各一次,损失可以忽略不计了。

修正后的源码:MvcIocDemo.rar(485KB)

后记

人非圣贤,难免犯错。

但截止到本文发布时,dudu 这篇文章却有 18 个推荐,只有 1 个反对(我的了),我们不得不反思了。

 

不华丽分割线

 

IoC在ASP.NET Web API中的应用

控制反转(Inversion of Control,IoC),简单地说,就是应用本身不负责依赖对象的创建和维护,而交给一个外部容器来负责。这样控制权就由应用转移到了外部IoC容器,控制权就实现了所谓的反转。比如在类型A中需要使用类型B的实例,而B实例的创建并不由A来负责,而是通过外部容器来创建。通过IoC的方式实现针对目标HttpController的激活具有重要的意义。[本文已经同步到《How ASP.NET Web API Works?》]

一、 基于IoC的HttpControllerActivator

将IoC应用于HttpController激活系统的目的在于让一个预定义的IoC容器来提供最终的HttpController对象。通过《ASP.NET Web API的Controller是如何被创建的?》的介绍我们知道HttpController的激活最终由HttpControllerActivator对象来完成,所以将IoC与ASP.NET Web API的HttpController激活系统进行集成最为直接的方式莫过于自定义一个HttpControllerActivator。

我们通过一个简单实例来演示如何通过自定义HttpControllerActivator的方式实现与IoC的集成,我们采用的IoC框架是Unity。我们在一个ASP.NET Web API应用中定义了这个UnityHttpControllerActivator类型。UnityHttpControllerActivator具有一个表示Unity容器的属性UnityContainer,该属性在构造函数中被初始化。在用于创建的HttpController的Create方法中,我们调用此UnityContainer对象的Resolve方法创建目标HttpController对象。

   1: public class UnityHttpControllerActivator : IHttpControllerActivator
   2: {
   3:     public IUnityContainer UnityContainer { get; private set; }
   4:  
   5:     public UnityHttpControllerActivator(IUnityContainer unityContainer)
   6:     {        
   7:         this.UnityContainer = unityContainer;
   8:     }
   9:  
  10:     public  IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
  11:     {
  12:         return (IHttpController)this.UnityContainer.Resolve(controllerType);
  13:     }
  14: }

接下来我们定义了如下一个继承自ApiController的ContactsController来管理联系人信息。简单起见,我们只定义了唯一的Action方法Get用于获取联系人信息。该方法具有一个可缺省的参数id表示希望获取的联系人的ID,如果没有提供此参数则返回所有联系人列表。

   1: public class ContactsController : ApiController
   2: {
   3:     public IContactRepository Repository { get; private set; }
   4:     public ContactsController(IContactRepository repository)
   5:     {
   6:         this.Repository = repository;
   7:     }
   8:     public IEnumerable<Contact> Get(string id = "")
   9:     {
  10:         return this.Repository.GetContacts(contact => 
  11:             string.IsNullOrEmpty(id) || id == contact.Id);
  12:     }
  13: }
  14:  
  15: public class Contact
  16: {
  17:     public string Id { get; set; }
  18:     public string Name { get; set; }
  19:     public string PhoneNo { get; set; }
  20:     public string EmailAddress { get; set; }
  21:     public string Address { get; set; }
  22: }

Action方法利用Repository属性返回的对象来实施联系人的查询工作,这个IContactRepository接口类型的属性在构造函数中初始化。我们利用IContactRepository接口来抽象对联系人数据的存储,如下面的代码片断所示,我们在此接口中仅定义了唯一的GetContacts方法根据指定的添加来筛选对应的联系人列表。

   1: public interface IContactRepository
   2: {
   3:     IEnumerable<Contact> GetContacts(Predicate<Contact> predicate);
   4: }

我们定义了如下一个DefaultContactRepository类型作为IContactRepository接口的默认实现者,简单起见,我们采用一个静态字典来保存联系人列表。

   1: public class DefaultContactRepository : IContactRepository
   2: {
   3:     private static List<Contact> contacts = new List<Contact>
   4:     {
   5:         new Contact{ Id="001", Name = "张三",  PhoneNo="123", EmailAddress = "zhangsan@gmail.com"},
   6:         new Contact{ Id="002", Name = "李四",  PhoneNo="456",EmailAddress = "lisi@gmail.com"}
   7:     };
   8:  
   9:     public IEnumerable<Contact> GetContacts(Predicate<Contact> predicate)
  10:     {
  11:         return contacts.Where(contact=>predicate(contact));
  12:     }
  13: }

我们在Global.asax中对自定义的UnityHttpControllerActivator进行了注册。如下面的代码片断所示,我们在Application_Start方法中创建了一个UnityContainer对象,并通过调用泛型方法RegisterType<TFrom,TTo>注册了IContactRepository接口和DefaultContactRepository类型之间的匹配关系。我们最后根据这个UnityContainer创建一个UnityHttpControllerActivator对象,并将其注册到当前ServicesContainer上。

   1: public class WebApiApplication: System.Web.HttpApplication
   2: {
   3:     protected void Application_Start()
   4:     {
   5:         //其他操作
   6:         IUnityContainer unityContainer = new UnityContainer();
   7:         unityContainer.RegisterType<IContactRepository,   DefaultContactRepository>(); 
   8:         GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new UnityHttpControllerActivator(unityContainer));
   9:     }
  10: }

当此ASP.NET Web API应用运行之后,我们可以直接在浏览器中输入相应的地址获取所有联系人列表(“/api/contacts”)和针对某个ID为“001”(“/api/contacts/001”)的联系人信息,相应的联系人信息会以如下图所示的形式出现在浏览器上。

二、基于IoC的DependencyResolver

由于默认的DefaultHttpControllerActivator会先利用当前注册的DependencyResolver对象去激活目标HttpController,所以除了利用自定义的HttpControllerActivator将IoC引入HttpController激活系统之外,另一个有效的方案就是注册自定义的DependencyResolver。

接下来将要自定义的DependencyResolver基于另一个叫作“Ninject”的IoC框架。较之Unity,Ninject是一个更加轻量级的IoC框架。篇幅所限,我们不便对这个IoC框架作过多的介绍,有兴趣的读者可以访问其官网(“http://www.ninject.org/”)了解Ninject。

   1: public class NinjectDependencyResolver : IDependencyResolver
   2: {
   3:     private List<IDisposable> disposableServices = new List<IDisposable>();
   4:     public IKernel Kernel { get; private set; }
   5:  
   6:     public NinjectDependencyResolver(NinjectDependencyResolver parent)
   7:     {
   8:         this.Kernel = parent.Kernel;
   9: }
  10:  
  11:     public NinjectDependencyResolver()
  12:     {
  13:         this.Kernel = new StandardKernel();
  14:     }
  15:  
  16:     public void Register<TFrom, TTo>() where TTo : TFrom
  17:     {
  18:         this.Kernel.Bind<TFrom>().To<TTo>();
  19: }
  20:  
  21:     public IDependencyScope BeginScope()
  22:     {
  23:         return new NinjectDependencyResolver(this);
  24:     }
  25:  
  26:     public object GetService(Type serviceType)
  27:     {
  28:         return this.Kernel.TryGet(serviceType);
  29:     }
  30:  
  31:     public IEnumerable<object> GetServices(Type serviceType)
  32:     {
  33:         foreach (var service in this.Kernel.GetAll(serviceType))
  34:         {
  35:             this.AddDisposableService(service);
  36:             yield return service;
  37:         }
  38: }    
  39:  
  40:     public void Dispose()
  41:     {
  42:         foreach (IDisposable disposable in disposableServices)
  43:         {
  44:             disposable.Dispose();
  45:         }
  46: }
  47:  
  48:     private void AddDisposableService(object servie)
  49:     {
  50:         IDisposable disposable = servie as IDisposable;
  51:         if (null != disposable && !disposableServices.Contains(disposable))
  52:         {
  53:             disposableServices.Add(disposable);
  54:         }
  55:     }
  56: }

我们创建了如上一个类型为NinjectDependencyResolver的自定义DependencyResolver。NinjectDependencyResolver的核心是类型为IKernel的只读属性Kernel,用于获取服务实例的GetService和GetServices方法分别通过调用此Kernel属性的TryGet和GetAll方法来实现。BeginScope方法返回一个新的NinjectDependencyResolver对象,它与自身拥有同一个Kernel对象。我们定义了额外的方法Register<TFrom,TTo>来注册接口与实现类型之间的映射关系。为了确保获取的服务实例能够被正常地释放,我们定义了一个元素类型为IDisposable的列表。如果获取的对象实现了IDisposable接口,它会被放入这个列表中,我们在实现的Dispose方法中释放该列表中的所有对象。

现在我们将这个自定义的NinjectDependencyResolver应用到上一个演示实例中。我们只需要将Global.asax中针对自定义HttpControllerActivator的注册替换成针对NinjectDependencyResolver的注册即可。运行此ASP.NET Web API应用后通过浏览器试图获取联系人信息,我们依然会得到如上图所示的结果。

   1: public class MvcApplication : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start()
   4:     {
   5:         //其他操作
   6:         NinjectDependencyResolver dependencyResolver = new NinjectDependencyResolver();
   7:         dependencyResolver.Register<IContactRepository, DefaultContactRepository>();
   8:         GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver; 
   9:     }
  10: }

 

 

不华丽分割线

为ASP.NET MVC创建一个基于Unity的ControllerFactory

谈到IoC和ASP.NET的集成,很多人会先后想到Ninject,不过我们个人还是倾向于Unity。这篇文章简单地介绍如果创建基于Unity的ControllerFactory。如下面的代码所示,我们通过直接继承DefaultControllerFactory创建一个自定的UnityControllerFactory。构造函数指定的是配置的UnityContainer的名称,如果没有显式指定则采用默认的UnityContainer。在重写的GetControllerInstance方法中,直接调用IUnityContainer的Resolve方法根据Controller类型创建相应的对象。[源代码从这里下载]

   1: public class UnityControllerFactory: DefaultControllerFactory
   2: {
   3:     public IUnityContainer Container { get; private set; }
   4:     public UnityControllerFactory(string containerName = "")
   5:     {
   6:         IUnityContainer container = new UnityContainer();
   7:         UnityConfigurationSection configSection = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection;
   8:         if (null == configSection && !string.IsNullOrEmpty(containerName))
   9:         {
  10:             throw new ConfigurationErrorsException("Cannot find <unity> configuration section");
  11:         }
  12:  
  13:         if (string.IsNullOrEmpty(containerName))
  14:         {
  15:             configSection.Configure(container);
  16:         }
  17:         else
  18:         {
  19:             configSection.Configure(container, containerName);
  20:         }
  21:         this.Container = container;
  22:     }
  23:     protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
  24:     {
  25:         Guard.ArgumentNotNull(controllerType, "controllerType");
  26:         return (IController)this.Container.Resolve(controllerType);
  27:     }
  28: }

为了演示DefaultControllerFactory的作用,我们来创建一个简单的例子。假设我们要创建一个维护联系人的应用,我们通过具有如下定义的Contact类型表示联系人,而IContactRepository接口定义了一个从存储中获取所有联系人的GetAllContacts方法,DefaultContactRepository是对IContactRepository接口的实现。

   1: public class Contact
   2: {
   3:     public string Name { get; set; }
   4:     public string Gender { get; set; }
   5:     public string Address { get; set; }
   6: }
   7:  
   8: public interface IContactRepository
   9: {
  10:     IEnumerable<Contact> GetAllContacts();
  11: }
  12:  
  13: public class DefaultContactRepository : IContactRepository
  14: {
  15:     public IEnumerable<Contact> GetAllContacts()
  16:     {
  17:         yield return new Contact
  18:         {
  19:             Name = "Zhang San",
  20:             Gender = "Male",
  21:             Address = "#328, XingHu Street, Su Zhou, Jiang Su Province, PRC."
  22:         };
  23:  
  24:         yield return new Contact
  25:         {
  26:             Name = "Li Si",
  27:             Gender = "Female",
  28:             Address = "#328, Jin Ji Hu Road, Su Zhou, Jiang Su Province, PRC."
  29:         };
  30:     }
  31: }

我们在Web应用的主页显示联系人列表,为此我创建了如下一个HomeController。在这里我们演示的是构造器注入,所以我们通过构造函数指定的IContactRepository对象来初始化Repository属性。在Action方法Index中调用IContactRepository的GetAllContacts方法为对应的View指定Model。

   1: public class HomeController : Controller
   2: {
   3:     public IContactRepository Repository { get; private set; }
   4:     public HomeController(IContactRepository repository)
   5:     {
   6:         this.Repository = repository;
   7:     }
   8:     public ActionResult Index()
   9:     {
  10:         return View(this.Repository.GetAllContacts());
  11:     }
  12: }

Index.cshtml代码如下所示,这是一个Model类型为IEnumerable<Contact>的View,它将所有的联系人信息列出来。

   1: @model IEnumerable<Artech.Web.Mvc.Extensions.Contact>
   2: @{
   3:     ViewBag.Title = "Index";
   4: }
   5:  
   6: <h2>Contact List</h2>
   7:  
   8: <div>
   9: <ul>
  10: @foreach (var contact in this.Model)
  11: { 
  12:     <li>
  13:         <h3>@contact.Name</h3>
  14:         <p>Gender: @contact.Gender</p>
  15:         <p>Address: @contact.Address</p>
  16:         <hr />
  17:     </li>
  18: }
  19: </ul>
  20: </div>

自定义的UnityContainerFactory的注册定义在Gloable.asax中。初次之外,额外需要做的是忽略掉针对favicon.ico的路由,否则程序运行将会失败。

   1: public class MvcApplication : System.Web.HttpApplication
   2: {
   3:     public static void RegisterGlobalFilters(GlobalFilterCollection filters)
   4:     {
   5:         filters.Add(new HandleErrorAttribute());
   6:     }
   7:  
   8:     public static void RegisterRoutes(RouteCollection routes)
   9:     {
  10:         routes.IgnoreRoute("favicon.ico");
  11:         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  12:         routes.MapRoute("Default", "{controller}/{action}/{id}",
  13:             new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
  14:         );
  15:     }
  16:  
  17:     protected void Application_Start()
  18:     {
  19:         AreaRegistration.RegisterAllAreas();
  20:         RegisterGlobalFilters(GlobalFilters.Filters);
  21:         RegisterRoutes(RouteTable.Routes);
  22:  
  23:         ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory());
  24:     }
  25: }

接口IContactRepository和DefualtContactRepository之间的映射关系定义在如下所示的<unity>配置中。

   1: <unity>
   2:   <alias alias="IContactRepository" type="Artech.Web.Mvc.Extensions.IContactRepository, UnityIntegration" />
   3:   <alias alias="DefaultContactRepository" type="Artech.Web.Mvc.Extensions.DefaultContactRepository, UnityIntegration" />
   4:   <container>
   5:     <register type="IContactRepository" mapTo="DefaultContactRepository"/>
   6:   </container>
   7: </unity>

通过浏览器访问Web应用的主页,将会得到如下所示的联系人列表。

image

 

 

 

 

 

分享到:
评论

相关推荐

    ASP.NET MVC4 Web 编程

    在ASP.NET MVC4中,**Model**代表应用程序的核心业务逻辑和数据,它与数据库或其他数据源进行交互。开发者可以使用Entity Framework或NHibernate等ORM工具来简化数据访问层的开发。 **View**是用户界面部分,负责...

    ASP.NET MVC如何使用Unity实现Ioc详解

    2. 创建模型(Model)、视图(View)、控制器(Controller)以及接口和实现类:这是创建MVC应用的标准步骤,我们需要定义好这些组件,以及它们之间的依赖关系。 3. 使用Unity容器进行依赖注册:在项目中配置Unity...

    ASP.NET MVC4 Web 编程.pdf

    9. **Dependency Injection (DI)** 和 **Inversion of Control (IoC)**:ASP.NET MVC4支持依赖注入,通过IoC容器,如Unity或 Ninject,实现解耦和可扩展性。 10. **Templating**:内置的模板机制简化了用户注册、...

    ASP.NET MVC 5高级编程

    9. **WebAPI集成**:ASP.NET MVC 5还包括Web API框架,使得构建RESTful服务变得简单。Web API可以与MVC共享同一个项目,提供前后端分离的应用架构。 10. **数据库迁移(Database Migrations)**:使用Entity ...

    ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统

    它结合了ASP.NET Web Forms和ASP.NET Web API的功能,提供了更灵活的开发方式。MVC5支持razor视图引擎,允许开发者用更加简洁的语法编写视图代码。此外,它还增强了身份验证和授权功能,包括OAuth2和Windows Azure ...

    asp.net mvc 4

    10. **WebAPI**:ASP.NET Web API是ASP.NET MVC 4的一部分,专为RESTful服务设计,书籍可能会讲解如何创建和消费Web API。 《20 Recipes for Programming MVC 3》则可能是一本以问题解答形式编写的书,提供了20个...

    ASP.NET MVC 4高级编程

    9. **WebAPI**:ASP.NET Web API是构建RESTful服务的框架,它可以与ASP.NET MVC 4无缝集成,为创建面向HTTP的服务提供强大支持。 10. **依赖注入**:ASP.NET MVC 4支持依赖注入(DI),通过DI,可以实现对象间的...

    ASP.NET MVC 5高级编程 第5版

    13. **WebAPI集成**:ASP.NET MVC 5同时支持Web应用程序和Web API开发,使得在同一项目中构建RESTful服务变得简单。 14. **响应式设计**:通过Bootstrap等前端框架,ASP.NET MVC 5项目可以轻松实现响应式布局,确保...

    ASP.net MVC 4 框架揭秘

    10. **Web API**:ASP.NET MVC 4还包括Web API,这是一个用于构建RESTful服务的框架,使得构建和消费HTTP服务变得更加简单,可以用来创建面向Web服务的应用。 通过学习《ASP.NET MVC 4框架揭秘》,开发者可以全面...

    ·ASP.NET MVC 4 高级编程

    另外,还会涉及依赖注入(DI)和控制反转(IoC)的概念,以及如何使用Unity或Autofac等容器来实现这些原则,以提高代码的可扩展性和可维护性。 在安全性方面,ASP.NET MVC 4提供了身份验证和授权机制,包括Forms...

    ASP NET MVC 4 Web编程(带目录)

    本教程将深入探讨ASP.NET MVC 4的关键概念和技术,帮助开发者快速掌握这一强大的Web开发工具。 一、MVC模式解析 模型-视图-控制器(MVC)是一种设计模式,用于分离应用程序的业务逻辑、数据处理和用户界面。在ASP...

    AspNetMVC3Setup.exe --.net MVC 3模板安装+汉化

    另外,WebAPI是ASP.NET MVC 3的一个扩展,专门用于构建RESTful服务,便于创建面向移动设备和现代Web应用的服务端接口。 9. **NuGet包管理器**:NuGet是.NET社区广泛使用的包管理工具,ASP.NET MVC 3集成了NuGet,...

    Asp.net MVC3.0教程

    2. **MVC和WebAPI结合**:学习如何在同一个项目中使用MVC处理UI请求,WebAPI处理API请求。 3. **依赖注入(IOC)**:理解依赖注入容器,如Unity或Autofac,提升代码的可测试性和可维护性。 4. **单元测试(Unit ...

    Professional ASP.NET MVC 4

    - **ASP.NET MVC 4**:是ASP.NET MVC系列中的一个版本,相比之前的版本,在性能和功能上都有显著提升,特别是在响应式设计、移动优化等方面有所增强。 #### 二、控制器(Controllers) - **定义**:控制器是负责...

    MVC 实例(代码)

    在"Demo"这个压缩包文件中,很可能是包含了一个完整的ASP.NET MVC 3项目实例,可能包括了控制器(Controllers)、视图(Views)和模型(Models)文件,以及相关的配置文件(Web.config)。通过研究这些示例代码,你...

    ASP.NET+MVC+4

    4. **依赖注入(DI)**与**控制反转(IoC)**:ASP.NET MVC 4支持DI和IoC,通过容器如Unity或Autofac,可以使组件之间解耦,提高代码的可测试性和可维护性。 5. **单元测试和TDD**:MVC架构鼓励编写可测试的代码,...

    MVC.net + IOC(Ninject) 示例源码

    在.NET世界中,常见的IOC容器有Autofac、Unity和Ninject等。 **三、Ninject - 一个流行的IOC容器** Ninject是轻量级且高性能的IOC容器,用于.NET平台。它通过依赖注入(DI)实现IOC,帮助开发者更轻松地管理对象间...

    asp.net+ef 多层+ioc 左侧菜单通用模板

    在ASP.NET中,可以使用Unity、Autofac等第三方DI容器,或者内置的依赖注入框架,来管理服务实例的创建和生命周期。 5. **左侧菜单通用模板**:在Web应用中,左侧菜单通常是用户导航的重要部分。这个模板可能包含了...

    diving-into-Asp-Net-webapi

    在*** Web API中使用Unity容器和依赖注入可以将应用程序中的依赖关系解耦,使得单元测试和模块替换更加容易。 在书中,作者也讨论了如何设置业务服务项目和Web API项目,以及如何运行应用程序。他还分析了现有设计...

    MVC4SampleCode.zip 353MB的资料包,拥有丰富的源代码

    通过深入研究"MVC4SampleCode.zip"中的源代码,开发者不仅可以掌握ASP.NET MVC 4的基本原理,还能了解到最佳实践和常见设计模式,从而提升Web开发技能。同时,这些示例代码也是解决实际问题的宝贵参考资料,对于进阶...

Global site tag (gtag.js) - Google Analytics