如何在ASP.NET MVC 5应用的Area中向IoC容器注册类型?
在ASP.NET MVC 5的Area中使用Unity.Mvc注册专属依赖类型
我之前也碰到过一模一样的需求——不同Area需要注册自己独有的服务,不想把所有注册逻辑都堆在全局的UnityConfig里。下面是我实践过的可行方案,步骤清晰好维护:
第一步:让Unity容器全局可访问
默认的UnityConfig里,容器是局部变量,Area根本拿不到。所以我们要把它改成静态属性,方便其他模块调用:
public static class UnityConfig { // 把容器暴露为静态属性,供Area调用 public static IUnityContainer Container { get; private set; } public static void RegisterTypes() { Container = new UnityContainer(); // 这里放全局通用的依赖注册,比如整个项目都用的基础服务 Container.RegisterType<IGlobalLoggingService, GlobalLoggingServiceImpl>(); // 最后设置依赖解析器 DependencyResolver.SetResolver(new UnityDependencyResolver(Container)); } }
第二步:为每个Area创建专属的注册类
在你的Area目录下,比如Areas/Admin/,新建一个类似AdminUnityConfig.cs的类,专门处理这个Area的依赖注册:
public static class AdminUnityConfig { public static void RegisterAreaServices(IUnityContainer container) { // 这里只注册Admin Area独有的服务 container.RegisterType<IAdminDashboardService, AdminDashboardServiceImpl>(); container.RegisterType<IAdminUserRepository, AdminUserDbRepository>(); } }
第三步:在Area启动时执行注册
每个Area都有对应的AreaRegistration类(比如AdminAreaRegistration.cs),我们可以在它的RegisterArea方法里调用上面的注册方法——这个方法会在应用启动时自动执行,时机刚好:
public class AdminAreaRegistration : AreaRegistration { public override string AreaName => "Admin"; public override void RegisterArea(AreaRegistrationContext context) { // 保留原来的路由注册代码 context.MapRoute( "Admin_default", "Admin/{controller}/{action}/{id}", new { action = "Index", id = UrlParameter.Optional } ); // 调用Area专属的Unity注册逻辑 AdminUnityConfig.RegisterAreaServices(UnityConfig.Container); } }
关键注意点:启动顺序不能乱
在Global.asax的Application_Start里,必须先初始化Unity容器,再注册所有Area,不然Area注册时会拿到空的容器:
protected void Application_Start() { // 1. 先初始化Unity容器 UnityConfig.RegisterTypes(); // 2. 再注册所有Area(此时每个Area的RegisterArea会执行,调用自己的注册方法) AreaRegistration.RegisterAllAreas(); // 后面是其他常规配置 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); }
进阶方案:自动扫描注册(适合多Area项目)
如果你的项目有很多Area,手动在每个AreaRegistration里调用注册方法太麻烦,可以用自动扫描的方式:
- 定义一个统一的接口:
public interface IUnityAreaRegistrar { void RegisterTypes(IUnityContainer container); }
- 让每个Area的注册类实现这个接口:
public class AdminUnityConfig : IUnityAreaRegistrar { public void RegisterTypes(IUnityContainer container) { // 注册Admin Area的服务 } }
- 在UnityConfig里扫描所有实现了该接口的类并自动执行注册:
public static void RegisterTypes() { Container = new UnityContainer(); // 全局注册... // 自动扫描所有Area的注册类 var registrarTypes = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => assembly.GetTypes()) .Where(type => typeof(IUnityAreaRegistrar).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract); foreach (var type in registrarTypes) { var registrar = (IUnityAreaRegistrar)Activator.CreateInstance(type); registrar.RegisterTypes(Container); } DependencyResolver.SetResolver(new UnityDependencyResolver(Container)); }
这样就不用手动维护每个Area的注册调用了,新增Area时只要实现接口就行。
内容的提问来源于stack exchange,提问作者Jaylen
相关产品推荐
相关产品推荐

