Исходя из ваших комментариев, настоящим я пересматриваю свой ответ :)
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
универсальным фабричным делегатом, как я описал здесь .