启动我的 MVC 应用程序时,会立即调用UnityMvcActivator
,它会实例化、配置容器并将其设置为依赖项解析器:
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
类时,我无法从DependencyResolver
中取回容器 - 这是所有其他初始化发生的地方 - 那么如何注册这些类型?
编辑:
我认为我很聪明,我尝试通过添加此程序集指令并将我的配置方法调用移动到新创建的方法来向激活器添加一些启动后操作:
[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 问题,因为所有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
//...
}