Autofac свойство инъекции - PullRequest
       25

Autofac свойство инъекции

6 голосов
/ 05 октября 2011

Я нахожусь в процессе изменения моего проекта Asp.Net MVC3 для использования Autofac для внедрения услуг в мои контроллеры.Пока это было довольно просто.Все мои сервисы имеют свойство db Telerik OpenAccess, которое я внедряю через конструкторы (в базовом классе обслуживания).И все мои контроллеры имеют свойства конструктора для сервисов, которые также вводятся.

У меня есть класс AuditInfo, который инкапсулирует контролируемые свойства контроллера:

public class AuditInfo
{      
    public string RemoteAddress { get; set; }

    public string XForwardedFor { get; set; }

    public Guid UserId { get; set; }

    public string UserName { get; set; }
}

Мое свойство базы данных OpenAccess в моем сервисеклассы должны иметь экземпляр этого класса, внедренный в него для использования в качестве информации аудита в различных вызовах базы данных.

Проблема в том, что это не тот класс, который может быть создан в Application_Start, потому что как минимум два его свойства, RemoteAddress и XForwardedFor, заполняются на самой ранней стадии OnActionExecuting, т. Е. Когда существуют переменные запроса.

Поэтому я создаю это в методе OnActionExecuting моего класса BaseController следующим образом:

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    base.OnActionExecuting(filterContext);
    db.AuditInfo = AuditInfo;                                      
}

public AuditInfo AuditInfo
{
    get
    {
        return new AuditInfo()
        {
            RemoteAddress = this.Request.ServerVariables["REMOTE_ADDR"],
            XForwardedFor = this.Request.ServerVariables["X_FORWARDED_FOR"],
            UserId = this.UserId,
            UserName = this.UserName
        };
    }
}

Итак, мои проблемы / вопросы:

  1. Не знаюкак этот прямой доступ к свойству db OpenAccess в OnActionExecuting.
  2. Я бы хотел, чтобы этот AuditInfo в основном внедрялся в любое свойство AuditInfo в любом месте
  3. Я не думаю, что могу использовать конструкторвнедрение для AuditInfo, поскольку службы зависят от db - контроллеры зависят от служб - db зависит от AuditInfo, НО AuditInfo недоступен, пока не будет создан экземпляр контроллера и не получит свой первый запрос.=> циклическая зависимость ...

Как мне настроить автозапуск для внедрения AuditInfo в любой класс, который имеет это свойство?Или есть лучший способ обойти циклическую зависимость и использовать некоторую форму свойств конструктора lambda / lazy?

Это вообще касается того, что AuditInfo может быть повторно инициализирован потенциально без необходимости при каждом запросе, даже если много запросовможет быть частью одного сеанса и не иметь другого IP-адреса / информации о пользователе?

Спасибо

Ответы [ 2 ]

3 голосов
/ 06 октября 2011

Оказывается Интеграция MVC от Autofac может разрешить HttpRequestBase для вас .Поэтому вам не нужно ссылаться на HttpContext.Current.Request напрямую.

Реализация Autofac использует HttpContext.Current за кадром.Это работает, потому что инфраструктура MVC устанавливает HttpContext.Current до запуска вашего кода (или Autofac).Так что круговой зависимости нет - запрос «естественно существует» на HttpContext.Current.Request так же, как и в вашем контроллере.( Этот вопрос как бы объясняет, как)

Таким образом, вы можете сделать IAuditInfoFactory, как предлагает Стивен, но потребовать HttpRequestBase в своем конструкторе вместо использования HttpContext.Current, если это заставит васлучше не ссылаться на статические переменные.

Кроме того, нет циклической зависимости, и вы можете с помощью конструктора ввести AuditInfo, если хотите:

builder.Register(c => c.Resolve<IAuditInfoFactory>().CreateNew())
    .As<AuditInfo>()
    .InstancePerHttpRequest();
2 голосов
/ 05 октября 2011

Ответ: используйте фабрику.

Вставьте IAuditInfoFactory в тип, который нуждается в нем, и создайте реализацию, подобную этой:

public class HttpRequestAuditInfoFactory : IAuditInfoFactory
{
    // Service for requesting information about the current user.
    private readonly ICurrentUserServices user;

    public HttpRequestAuditInfoFactory(ICurrentUserServices user)
    {
        this.user = user;
    }

    AuditInfo IAuditInfoFactory.CreateNew()
    {
        var req = HttpContext.Current.Request;

        return new AuditInfo()
        {
            RemoteAddress = req.ServerVariables["REMOTE_ADDR"],
            XForwardedFor = req.ServerVariables["X_FORWARDED_FOR"],
            UserId = this.user.UserId,
            UserName = this.user.UserName
        };
    }
}

Вы можете зарегистрировать этот класс следующим образом:

builder.RegisterType<HttpRequestAuditInfoFactory>()
    .As<IAuditInfoFactory>()
    .SingleInstance();

Теперь вы можете вводить

...