Además, cada ModelValidation
instancia será atado a una instancia de ModelStateDictionary
y es por lo tanto también ser considerado como datos.
En Autofac, cuando los datos se deben pasar a los constructores (opcionalmente además de otras dependencias), debemos usar delegados de fábrica. Estos delegados manejarán la dependencia y el paso de datos al constructor. Lo dulce de Autofac es que estos delegados pueden autogenerarse.
propongo la siguiente solución:
Dado que tanto ModelValidation y CustomerService requiere datos en sus constructores, necesitamos dos delegados de fábrica (nota: los nombres de los parámetros deben coincidir con los nombres de sus correspondientes constructor):
public delegate IModelValidation ModelValidationFactory(ModelStateDictionary msd);
public delegate CustomerService CustomerServiceFactory(ModelStateDictionary msd);
Dado que los controladores no debe saber dónde viene delegados de estos deben ser pasados al constructor controlador como dependencias:
public class EditCustomerController : Controller
{
private readonly CustomerService _customerService;
public EditCustomerController(CustomerServiceFactory customerServiceFactory
/*, ...any other dependencies required by the controller */
)
{
_customerService = customerServiceFactory(this.ModelState);
}
}
El Servicio a Cliente debe tener un constructor similar a este (opcionalmente manejar algo de esto en una clase ServiceBase):
public class CustomerService
{
private readonly IModelValidation _modelValidation;
public CustomerService(ModelStateDictionary msd,
ModelValidationFactory modelValidationFactory)
{
_modelValidation = modelValidationFactory(msd);
}
para que esto suceda tenemos que construir nuestro contenedor de esta manera:
var builder = new ContainerBuilder();
builder.Register<ModelValidation>().As<IModelValidation>().FactoryScoped();
builder.Register<CustomerService>().FactoryScoped();
builder.RegisterGeneratedFactory<ModelValidationFactory>();
builder.RegisterGeneratedFactory<CustomerServiceFactory>();
builder.Register<EditCustomerController>().FactoryScoped();
Por lo tanto, cuando se resuelva el controlador (por ejemplo, al usar the MvcIntegration module), los delegados de fábrica serán inyectados en los controladores y servicios.
actualización: Para reducir el código necesario aún más, podría reemplazar CustomerServiceFactory
con un delegado de la fábrica genérico como he descrito here.
acaba de actualizar mi respuesta con una idea interesante que posiblemente le ahorrará de declarar un grupo de delegados de fábrica. –