Использование Unity для регистрации типов MVC, которые еще не существуют (пока) - PullRequest
0 голосов
/ 09 января 2019

UnityMvcActivator вызывается прямо из шлюза при запуске моего приложения MVC, и он создает, настраивает и устанавливает контейнер в 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;
}

Я не могу получить контейнер обратно из DependencyResolver, когда я наконец сделаю его в свой класс OWIN Startup - где и происходит вся остальная инициализация - так как я могу зарегистрировать эти типы?

EDIT:

Думая, что я умен, я попытался добавить какое-то действие после запуска к активатору, добавив эту директиву сборки и переместив вызов метода конфигурации во вновь созданный метод:

[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 все еще недоступны.

1 Ответ

0 голосов
/ 15 января 2019

Это скорее проблема 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
    //...
}
...