根据您的评论,我特此修改我的答案:)
ModelStateDictionary
显然不是应该由容器解析的服务,而是应该在实例化时提供的数据。我们可以从 ModelState 由每个 Controller 实例拥有的事实中看出这一点,因此在“解析时”容器不可用。
此外,每个ModelValidation
实例都将绑定到一个ModelStateDictionary
实例,因此也被视为数据。
在 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
我在这里描述的通用工厂委托替换。