2009-11-30 10 views
5

Tengo un contenedor en ModelStateDictionary que aceptan todos mis servicios. ¿Es posible configurar el autofac para inyectar el controlador ModelStateDictionary en el constructor del wrapper y luego inyectarlo en el constructor del servicio?¿Cómo pasar el ModelState del controlador al constructor de mi servicio con Autofac?

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

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

Gracias

+0

acaba de actualizar mi respuesta con una idea interesante que posiblemente le ahorrará de declarar un grupo de delegados de fábrica. –

Respuesta

8

Sobre la base de sus comentarios Por la presente revisar mi respuesta :)

ModelStateDictionary claramente no es un servicio deque debe ser resuelto por el contenedor, sino más bien datos que deben ser provisto en el momento de instanciación. Podemos decirlo por el hecho de que ModelState es propiedad de cada instancia de Controller y, por lo tanto, no está disponible para el contenedor en "resolver tiempo".

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.

+0

El contenedor crea un nuevo ModelStateDictionary y lo pasa al constructor de ModelValidation. Me gustaría pasar el ModelStateDictionary existente (al que se puede acceder mediante la propiedad Controller.ModelState) al constructor ModelValidation. ¿Es posible? – Valentin

+0

¿Podría explicar esto en su pregunta? ¿Controller.ModelState es estático? o cómo se declara hoy? –

+0

Controller.ModelState es una propiedad del tipo ModelStateDictionary. El controlador es creado por asp.net mvc runtime (fábrica del controlador), y el ModelStateDictionary se crea allí. Luego puedo crear mis controladores subclasificando el controlador y puedo acceder a la propiedad ModelState en mi clase. Si no estoy seguro, hágamelo saber y volveré a publicar mi pregunta con mayor detalle. – Valentin

0

Agregue un nuevo constructor sin ValidationService. Asigne ValidationService mediante el uso de una propiedad.

La propiedad se debe implementar en el ICostumerService interfaz

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; 
} 
1
Builder.RegisterInstance(new ModelStateDictionary()).SingleInstance(); 
      builder.Register(c => new SW.PL.Util.ModelStateWrapper 
(c.Resolve<ModelStateDictionary>())).As<IValidationDictionary>().InstancePerHttpRequest(); 
+0

Puede agregar como instancia única – Farid

+0

Esta pregunta hace mucho tiempo que ya no es real, lo siento. Ni siquiera programo .NET más :) – Valentin

Cuestiones relacionadas