.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

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值