使用 Unity 注册尚不存在的 MVC 类型
Using Unity to Register MVC Types That Don't Exist (Yet)
启动我的 MVC 应用程序时立即调用 UnityMvcActivator
,它实例化、配置容器并将其设置为 DependencyResolver:
DependencyResolver.SetResolver(new UnityDependencyResolver(UnityConfig.Container));
立即通过以下方式注册所有类型:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterMvcComponents();
}
...但我正在尝试注册直到稍后才创建的类型:
public static IUnityContainer RegisterMvcComponents(this IUnityContainer container)
{
var lifetimeManager = new HierarchicalLifetimeManager();
container.RegisterInstance<HttpSessionStateBase>(
new HttpSessionStateWrapper(HttpContext.Current.Session), lifetimeManager);
container.RegisterInstance<HttpContextBase>(
new HttpContextWrapper(HttpContext.Current), lifetimeManager);
container.RegisterInstance<HttpServerUtilityBase>(
new HttpServerUtilityWrapper(HttpContext.Current.Server), lifetimeManager);
container.RegisterInstance(HttpContext.Current.User.Identity, lifetimeManager);
return container;
}
当我最终到达我的 OWIN Startup
class 时,我无法从 DependencyResolver
取回容器 - 这是所有其他初始化发生的地方 -那么如何注册这些类型呢?
编辑:
自以为聪明,我尝试通过添加此汇编指令并将我的配置方法调用移动到新创建的方法来向激活器添加一些 post-start 操作:
[assembly: WebActivatorEx.PostApplicationStartMethod(
typeof(CCCS.Admin.Web.Ui.UnityMvcActivator),
nameof(CCCS.Admin.Web.Ui.UnityMvcActivator.PostStart))]
public static void PostStart() => UnityConfig.Container.RegisterMvcComponents();
...这让我走到了一半,但 User
和 Session
仍然不可用。
这更多的是 XY problem 与您的设计相关,因为所有 HttpContext
相关成员在启动时都不可用。
您最好创建抽象来推迟对这些实现问题的访问。
public interface IHttpContextAccessor {
HttpContextBase HttpContext { get; }
}
public class HttpContextProvider : IHttpContextAccessor {
public virtual HttpContextBase HttpContext {
get {
return new HttpContextWrapper(HttpContext.Current);
}
}
}
现在所有这些注册都可以替换为一个抽象,该抽象将提供对所有其他相关类型的访问。
public static IUnityContainer RegisterMvcComponents(this IUnityContainer container) {
var lifetimeManager = new HierarchicalLifetimeManager();
container.RegisterType<IHttpContextAccessor, HttpContextProvider>(lifetimeManager);
return container;
}
请注意,理想情况下,容器应该只在应用程序的组合根中访问,而不是作为依赖项传递。这被视为一种代码味道,并且表明应尽可能审查和重构设计。
当需要访问 HttpContext
相关成员时,现在只需注入访问器
private readonly IHttpContextAccessor accessor;
public MyDependent(IHttpContextAccessor accessor) {
this.accessor = accessor;
}
public void SomeMethodAccessedInAnAction() {
var context = access.HttpContext; // HttpContextBase
var session = context.Session; // HttpSessionStateBase
var server = context.Server; // HttpServerUtilityBase
var user = context.User; // IPrincipal
//...
}
启动我的 MVC 应用程序时立即调用 UnityMvcActivator
,它实例化、配置容器并将其设置为 DependencyResolver:
DependencyResolver.SetResolver(new UnityDependencyResolver(UnityConfig.Container));
立即通过以下方式注册所有类型:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterMvcComponents();
}
...但我正在尝试注册直到稍后才创建的类型:
public static IUnityContainer RegisterMvcComponents(this IUnityContainer container)
{
var lifetimeManager = new HierarchicalLifetimeManager();
container.RegisterInstance<HttpSessionStateBase>(
new HttpSessionStateWrapper(HttpContext.Current.Session), lifetimeManager);
container.RegisterInstance<HttpContextBase>(
new HttpContextWrapper(HttpContext.Current), lifetimeManager);
container.RegisterInstance<HttpServerUtilityBase>(
new HttpServerUtilityWrapper(HttpContext.Current.Server), lifetimeManager);
container.RegisterInstance(HttpContext.Current.User.Identity, lifetimeManager);
return container;
}
当我最终到达我的 OWIN Startup
class 时,我无法从 DependencyResolver
取回容器 - 这是所有其他初始化发生的地方 -那么如何注册这些类型呢?
编辑:
自以为聪明,我尝试通过添加此汇编指令并将我的配置方法调用移动到新创建的方法来向激活器添加一些 post-start 操作:
[assembly: WebActivatorEx.PostApplicationStartMethod(
typeof(CCCS.Admin.Web.Ui.UnityMvcActivator),
nameof(CCCS.Admin.Web.Ui.UnityMvcActivator.PostStart))]
public static void PostStart() => UnityConfig.Container.RegisterMvcComponents();
...这让我走到了一半,但 User
和 Session
仍然不可用。
这更多的是 XY problem 与您的设计相关,因为所有 HttpContext
相关成员在启动时都不可用。
您最好创建抽象来推迟对这些实现问题的访问。
public interface IHttpContextAccessor {
HttpContextBase HttpContext { get; }
}
public class HttpContextProvider : IHttpContextAccessor {
public virtual HttpContextBase HttpContext {
get {
return new HttpContextWrapper(HttpContext.Current);
}
}
}
现在所有这些注册都可以替换为一个抽象,该抽象将提供对所有其他相关类型的访问。
public static IUnityContainer RegisterMvcComponents(this IUnityContainer container) {
var lifetimeManager = new HierarchicalLifetimeManager();
container.RegisterType<IHttpContextAccessor, HttpContextProvider>(lifetimeManager);
return container;
}
请注意,理想情况下,容器应该只在应用程序的组合根中访问,而不是作为依赖项传递。这被视为一种代码味道,并且表明应尽可能审查和重构设计。
当需要访问 HttpContext
相关成员时,现在只需注入访问器
private readonly IHttpContextAccessor accessor;
public MyDependent(IHttpContextAccessor accessor) {
this.accessor = accessor;
}
public void SomeMethodAccessedInAnAction() {
var context = access.HttpContext; // HttpContextBase
var session = context.Session; // HttpSessionStateBase
var server = context.Server; // HttpServerUtilityBase
var user = context.User; // IPrincipal
//...
}