2009-06-12 12 views
7

Necesito ayuda. Estoy intentando usar un atributo de validación personalizado en un proyecto web ASP.NET MVC que necesita realizar una llamada a la base de datos.Inyección de base de datos en un atributo de validación con ASP MVC y Castle Windsor

Tengo windsor trabajando con éxito para los controladores y la interfaz de IRepository se inyecta normalmente. El problema surge cuando necesito inyectar el repositorio en la clase de atributo.

La clase de atributo tiene el siguiente código:

public class ValidateUniqueUrlNodeAttribute : AbstractValidationAttribute 
{ 
    private readonly string message; 
    private readonly IArticleRepository articleRepository; 

    public ValidateUniqueUrlNodeAttribute(string message) 
    { 
     this.message = message; 
    } 

    public ValidateUniqueUrlNodeAttribute(string message, IArticleRepository articleRepository):this(message) 
    { 
     this.articleRepository = articleRepository; 
    } 
    public override IValidator Build() 
    { 
     var validator = new UniqueUrlNodeValidator(articleRepository) { ErrorMessage = message }; 

     ConfigureValidatorMessage(validator); 

     return validator; 
    } 

Mi problema es que me parece que no puede hacer Windsor interceptar la contrucción del atributo a pasar en el IArticleRepository

El código actual en mi mundial El archivo .asax es el siguiente:

container = new WindsorContainer(); 
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container)); 
    container 
    .RegisterControllers(Assembly.GetExecutingAssembly()) 
    .AddComponent<IArticleRepository, ArticleRepository>() 
    .AddComponent<ValidateUniqueUrlNodeAttribute>(); 

Cualquier ayuda sería muy apreciada.

Respuesta

5

AFAIK ningún contenedor de inyección de dependencia puede gestionar directamente un atributo, ya que está instanciado por el tiempo de ejecución y no hay forma de interceptarlo.

Sin embargo, pueden engañar por cualquiera de:

  1. Usando una puerta de enlace estática al recipiente (example), o
  2. Uso de una característica de "acumulación" que inyecta lo dependencias se encuentran dentro de un ya -construido objeto. Esto se llama BuildUp in Unity o InjectProperties in Autofac.

Windsor no soporta # 2 (ref1, ref2), por lo que puede:

  1. probar uno de los hacks para hacer Windsor apoyo # 2 (hack1, hack2)
  2. Uso a static gateway
  3. Implemente su propio IValidatorBuilder y haga que use Windsor para crear validadores. Estoy seguro de que esto está implementado en algún lado pero no puedo encontrarlo ahora ...
+0

Muchas gracias. Opté por el número 1 que satisface mis necesidades perfectamente –

-1

Hmm.

¿Puedes probar el efecto de eliminar el (mensaje de cadena) ctor, y ver si eso al menos obliga a Castle a usar el ctor con el Repostiory?

De lo contrario, llamamos AddComponent (nombre, tipo, tipo). Aparte de eso, realmente debería funcionar ...

¿Esto también insinúa mi primera idea? How do I use Windsor to inject dependencies into ActionFilterAttributes

+0

Lo siento, no puedo quitar el CTOR cadena como el atributo tiene este aspecto cadena UrlNode {get; conjunto; } ¿Debería ser diferente? –

+0

Dahhh. Todavía rascándome la cabeza ... Voy a tener una búsqueda – penderi

0

No sabe si esto ayuda, pero con subclases ValidationAttribute para exponer un método Resolve<T>() así:

public abstract class IocValidationAttribute : ValidationAttribute 
{ 
    protected T Resolve<T>() 
    { 
     return IocHelper.Container().Resolve<T>(); 
    } 
} 

A continuación, se puede utilizar en cualquier costumbre ValidatorAttribute que necesita para golpear una base de datos:

public class UniqueEmailAttribute : IocValidationAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     ICustomerRepository customerRepository = Resolve<ICustomerRepository>(); 

     return customerRepository.FindByEmail(value.ToString()) == null; 
    } 
} 

Creo que es una variación del enfoque de "Puerta de enlace estática" mencionado por Mauricio Scheffer. No sé si este es un buen diseño o no. No soy un gran admirador de esto, preferiría que la dependencia se inyectara más 'elegantemente', aunque no puedo usar la inyección de constructor, obviamente, me gustaría usar la inyección de propiedad pero no puedo encontrar la forma de hacerlo. enganche en el código de marco ASP.NET MVC para hacer esto (incluso he estudiado minuciosamente el código fuente de MVC2).

+0

¿De dónde obtiene IocHelper? – soniiic

+3

@soniiic parece un mal estático –

0

pude cablear [Autofac utilizando como sucede, pero es sólo la inyección de constructor a través de la ASP.NET MVC DependencyResolver] in this answer, permitiendo a uno a escribir:

class MyModel 
{ 
    ... 
    [Required, StringLength(42)] 
    [ValidatorService(typeof(MyDiDependentValidator), ErrorMessage = "It's simply unacceptable")] 
    public string MyProperty { get; set; } 
    .... 
} 

public class MyDiDependentValidator : Validator<MyModel> 
{ 
    readonly IUnitOfWork _iLoveWrappingStuff; 

    public MyDiDependentValidator(IUnitOfWork iLoveWrappingStuff) 
    { 
     _iLoveWrappingStuff = iLoveWrappingStuff; 
    } 

    protected override bool IsValid(MyModel instance, object value) 
    { 
     var attempted = (string)value; 
     return _iLoveWrappingStuff.SaysCanHazCheez(instance, attempted); 
    } 
} 

Con algunas clases de ayuda (mira allí), lo conectas, p. ej. en ASP.NET MVC como tal en la Global.asax: -: pública [ValidateUniqueUrlNode ("Por favor, introduzca una URL única")]

DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(
    typeof(ValidatorServiceAttribute), 
    (metadata, context, attribute) => 
     new DataAnnotationsModelValidatorEx(metadata, context, attribute, true)); 
Cuestiones relacionadas