5

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

У меня есть класс с именем 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, то есть после того, как существуют переменные Request.

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

Как настроить autofac для вставки AuditInfo в любой класс, который имеет это свойство? Или есть лучший способ обойти круговую зависимость и использовать некоторую форму лямбда-ленивых свойств конструктора?

Действительно ли это связано с тем, что AuditInfo повторно инициализируется потенциально неоправданно при каждом запросе, даже если многие запросы могут быть частью одного и того же сеанса и не иметь другой адрес ip/user info?

Thanks

+0

Я не согласен с проблемой/вопросом 3 - а Стивен указует, вы можете использовать 'HttpContext.Current'. Поэтому 'AuditInfo' не зависит от контроллера, поэтому нет циклической зависимости, поэтому вы можете конструктор-вставить' AuditInfo', если хотите. –

+0

Ну, я думаю, это потому, что предлагаемое решение использует глобальную статическую переменную для ссылки на объект Request, а не на инициализацию объекта AuditInfo внутри контроллера, где естественно существует объект Request. Я думаю, что переменные сервера еще не существуют еще в Application_Start, где происходит инъекция, потому что действие нужно вызвать сначала, нет? – t316

ответ

2

Получается Autofac's MVC Integration can resolve an HttpRequestBase for you. Поэтому вам не нужно напрямую ссылаться на HttpContext.Current.Request.

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

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

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

builder.Register(c => c.Resolve<IAuditInfoFactory>().CreateNew()) 
    .As<AuditInfo>() 
    .InstancePerHttpRequest(); 
+0

Стивен отлично поработал над созданием правильного ответа, однако отсутствие инъекции HttpRequestBase и добавление default.kramer этого момента делает его ответ немного более полным. Не уверен - как я, судя по всему, справляюсь с справедливым обозначением правильного ответа в такой ситуации, пожалуйста, не стесняйтесь, дайте мне знать. На данный момент я отмечаю ответ default.kramer как правильный. благодаря – t316

2

Ответ: Использовать завод.

Вводят в 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(); 

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

+0

Спасибо за быстрый ответ. Это должно работать, но разве это решение не полагается на ссылку HttpContext.Current.Request и чтение переменных из него в чужом контексте, а не хранение необходимых переменных во время естественного жизненного цикла HttpContext.Current.Request и впрыска этих переменных в внешний контекст со свободной связью? Значение - реализация IAuditInfoFactory должна ссылаться на System.Web и напрямую знать о HttpContext.Current.Request, чтобы это работало ... – t316

+0

Эта конкретная реализация HttpRequestAuditInfoFactory действительно сильно зависит от 'HttpContext'. В этом смысле он осознает платформу. Это не проблема, но по этой причине она не является (или не должна быть) частью вашего приложения, но должна быть частью того, что мы называем [Roots of Composition] (http://blog.ploeh.dk/2011/ 07/28/CompositionRoot.aspx) (CR). Это путь запуска приложения. Ни одна другая часть, кроме CR, не должна знать о существовании этого «HttpRequestAuditInfoFactory». Приложение знает только об 'IAuditInfoFactory'. – Steven

+0

Поскольку остальная часть приложения знает о 'IAuditInfoFactory', но не о' HttpRequestAuditInfoFactory', это упрощает миграцию (часть) вашего приложения на, например, на службу Windows. Вам понадобится конкретная реализация службы Windows «IAuditInfoFactory» и подключите ее вместо «HttpRequestAuditInfoFactory» в CR («основной» метод) службы Windows. – Steven

Смежные вопросы