Как передать ModelState контроллера моему конструктору сервисов с помощью Autofac? - PullRequest
5 голосов
/ 30 ноября 2009

У меня есть оболочка для ModelStateDictionary, которую принимают все мои службы. Можно ли настроить автофак для внедрения контроллера ModelStateDictionary в конструктор оболочки, а затем внедрить его в конструктор службы?

//code
public class ModelValidation : IModelValidation { 
public ModelValidation(ModelStateDictionary msd){...}
..
..
}

public class CustomerService{
public CustomerService(IModelValidation mv){...}
..
}

Спасибо

Ответы [ 3 ]

9 голосов
/ 01 декабря 2009

Исходя из ваших комментариев, настоящим я пересматриваю свой ответ :)

ModelStateDictionary явно не является услугой , которая должна разрешаться контейнером, а скорее данными , которые должны предоставляться во время создания экземпляра. Мы можем сказать это по тому факту, что ModelState принадлежит каждому экземпляру Controller и, таким образом, недоступен для контейнера в «время разрешения».

Кроме того, каждый экземпляр ModelValidation будет связан с экземпляром ModelStateDictionary и, таким образом, также будет рассматриваться как data .

В Autofac, когда данные должны передаваться конструкторам (необязательно в дополнение к другим зависимостям), мы должны использовать фабричные делегаты. Эти делегаты будут обрабатывать зависимости и данные, передаваемые конструктору. Самое приятное в Autofac заключается в том, что эти делегаты могут генерироваться автоматически.

Я предлагаю следующее решение:

Поскольку для ModelValidation и CustomerService требуются данные в их конструкторах, нам нужны два фабричных делегата (примечание: имена параметров должны совпадать с именами в их соответствующем конструкторе):

public delegate IModelValidation ModelValidationFactory(ModelStateDictionary msd);
public delegate CustomerService CustomerServiceFactory(ModelStateDictionary msd);

Поскольку ваши контроллеры не должны знать, откуда происходят эти делегаты, они должны быть переданы в конструктор контроллера как зависимости:

public class EditCustomerController : Controller
{
    private readonly CustomerService _customerService;

    public EditCustomerController(CustomerServiceFactory customerServiceFactory
        /*, ...any other dependencies required by the controller */
          )
    {
        _customerService = customerServiceFactory(this.ModelState);
    }

}

CustomerService должен иметь конструктор, похожий на этот (опционально обрабатывать некоторые из них в классе ServiceBase):

public class CustomerService
{
    private readonly IModelValidation _modelValidation;

    public CustomerService(ModelStateDictionary msd,
              ModelValidationFactory modelValidationFactory)
    {
        _modelValidation = modelValidationFactory(msd);
    }

Чтобы это произошло, нам нужно построить наш контейнер следующим образом:

var builder = new ContainerBuilder();

builder.Register<ModelValidation>().As<IModelValidation>().FactoryScoped();
builder.Register<CustomerService>().FactoryScoped();

builder.RegisterGeneratedFactory<ModelValidationFactory>();
builder.RegisterGeneratedFactory<CustomerServiceFactory>();

builder.Register<EditCustomerController>().FactoryScoped();

Таким образом, при разрешении контроллера (например, при использовании модуля MvcIntegration ) делегаты фабрики будут внедрены в контроллеры и службы.

Обновление : чтобы еще больше сократить необходимый код, вы можете заменить CustomerServiceFactory универсальным фабричным делегатом, как я описал здесь .

1 голос
/ 10 марта 2012
Builder.RegisterInstance(new ModelStateDictionary()).SingleInstance();
            builder.Register(c => new SW.PL.Util.ModelStateWrapper
(c.Resolve<ModelStateDictionary>())).As<IValidationDictionary>().InstancePerHttpRequest(); 
0 голосов
/ 02 октября 2010

Добавить новый конструктор без ValidationService. Присвойте ValidationService с помощью свойства.

Свойство должно быть реализовано в интерфейсе ICostumerService

public class ModelStateWrapper: IValidationDictionary {  
public ModelStateWrapper(ModelStateDictionary msd){}
}

public class CustomerService: ICostumerService{
public IValidationDictionary ValidationDictionary { get; set; }
public CustomerService(ICustomerRepsitory customerRepository, IValidationDictionary validationDictionary ){} 
public CustomerService(ICustomerRepsitory customerRepository){}
}

public Controller(ICustomerService customerService)
{
  _customerService= menuService;
  _customerService.ValidationDictionary = new ModelStateWrapper(this.ModelState);
  _customerService= sportsService;
}
...