Pregunta

Descripción

Mi solución tiene estos proyectos:

  • DAL = Modificado Marco de la entidad
  • DTO objetos de transferencia de datos = que son capaces de validarse
  • BL Servicios = Capa de negocios
  • Web = presentación de aplicaciones Asp.net MVC

DAL, BL y WEB toda referencia DTO que es grande.
El proceso generalmente se ejecuta de esta manera:

  1. Una solicitud web se hace a la WEB
  2. WEB consigue dtos publicados
    • dtos consiguen automagicamente validados a través de encargo ActionFilter
    • errores de validación son auto-recogido
  3. (La validación es OK) WEB pone en BL proporcionan dtos
  4. BL pone en DAL mediante el uso de DTO (puede o bien pasar a través de o simplemente utilizar ellos)

problema DTO Validación entonces ...

Mis DTO son capaces de validarse en base a su propio estado (valores de las propiedades). Pero en este momento me presentan con un problema cuando este no es el caso. Los necesito para validar el uso de BL (y en consecuencia DAL).

Mi ejemplo real : Registros de usuario y WEB consigue un DTO usuario que obtiene validada. La parte problemática es la validación username. Su singularidad deberá cotejarse con la memoria de datos.
¿Cómo se supone que voy a hacer esto?

Hay información adicional que todos los dtos implementar una interfaz (es decir. User DTO implementa IUser) con fines COI y TDD. Ambos son parte del proyecto DTO .

intentos imposibles

  1. No puedo hacer referencia BL en DTO porque voy a conseguir referencia circular.
    Compilation error
  2. No puedo crear un proyecto DTO.Val adicional que hacer referencia a las clases parciales DTO y poner en práctica su validación allí (que habían Referencia BL + DTO).
    Partial classes can't span assemblies.

intentos posibles

  1. Crear un ActionFilter especial que validaría objeto contra las condiciones externas. Éste se crearía dentro de proyecto web ver tanto DTO y BL que se utilizaría aquí.
  2. Poner en dtos BL y mantener las interfaces DTO como DTO reales referenciados por otros proyectos y refactorizar todo el código para utilizar las interfaces en lugar de clases concretas.
  3. No manipule la validación externa dependientes y dejar las dependencias externas lanzan una excepción - probablemente el peor solución a este problema

¿Qué sugieres?

¿Fue útil?

Solución 4

solución resultante

Terminé usando filtro de acción del controlador que fue capaz de validar objeto contra factores externos que no se pueden obtener a partir del objeto en sí.

I creado el filtro que lleva el nombre del parámetro de acción para comprobar y tipo validador que validará ese parámetro particular. Por supuesto, esto validador ha de implementar determinada interfaz para hacer que todo reutilizable.

[ValidateExternalFactors("user", typeof(UserExternalValidator))]
public ActionResult Create(User user)

validador debe implementar esta interfaz sencilla

public interface IExternalValidator<T>
{
    bool IsValid(T instance);
}

Es una solución simple y eficaz a un problema aparentemente complejo.

Otros consejos

Yo sugeriría un experimento que sólo he estado probando durante la última semana o así.

estoy creando dtos que validan un poco diferente a el del enfoque DataAnnotations. DTO de la muestra:

public class Contact : DomainBase, IModelObject
{
    public int ID { get; set; }
    public string Name { get; set; }
    public LazyList<ContactDetail> Details { get; set; }
    public DateTime Updated { get; set; }


    protected override void ConfigureRules()
    {
        base.AddRule(new ValidationRule()
        {
            Properties = new string[] { "name" },
            Description = "A Name is required but must not exceed 300 characters in length and some special characters are not allowed",
            validator = () => this.Name.IsRequired300LenNoSpecial()
        });

        base.AddRule(new ValidationRule()
        {
            Properties = new string[] { "updated" },
            Description = "required",
            validator = () => this.Updated.IsRequired()
        });
    }
}

Esto puede parecer más trabajo que DataAnnotations y bien, eso es coz que es, pero no es enorme. Creo que es más presentable en la clase (tengo algunas clases DTO realmente feas ahora con atributos DataAnnotations - ni siquiera se puede ver las propiedades más). Y el poder de los delegados anónimos en esta aplicación es casi digno de libro (así que estoy descubriendo).

Clase base:

public partial class DomainBase : IDataErrorInfo
{
    private IList<ValidationRule> _rules = new List<ValidationRule>();

    public DomainBase()
    {
        // populate the _rules collection
        this.ConfigureRules();
    }

    protected virtual void ConfigureRules()
    {
        // no rules if not overridden
    }

    protected void AddRule(ValidationRule rule)
    {
        this._rules.Add(rule);
    }





    #region IDataErrorInfo Members

    public string Error
    {
        get { return String.Empty; }    // Validation should call the indexer so return "" here
    }                                   // ..we dont need to support this property.

    public string this[string columnName]
    {
        get
        {
            // get all the rules that apply to the property being validated
            var rulesThatApply = this._rules
                .Where(r => r.Properties.Contains(columnName));

            // get a list of error messages from the rules
            StringBuilder errorMessages = new StringBuilder();
            foreach (ValidationRule rule in rulesThatApply)
                if (!rule.validator.Invoke())   // if validator returns false then the rule is broken
                    if (errorMessages.ToString() == String.Empty)
                        errorMessages.Append(rule.Description);
                    else
                        errorMessages.AppendFormat("\r\n{0}", rule.Description);

            return errorMessages.ToString();
        }
    }

    #endregion
}

funciones ValidationRule y mi validación:

public class ValidationRule
{
    public string[] Properties { get; set; }
    public string Description { get; set; }
    public Func<bool> validator { get; set; }
}


/// <summary>
/// These extention methods return true if the validation condition is met.
/// </summary>
public static class ValidationFunctions
{
    #region IsRequired

    public static bool IsRequired(this String str)
    {
        return !str.IsNullOrTrimEmpty();
    }

    public static bool IsRequired(this int num)
    {
        return num != 0;
    }

    public static bool IsRequired(this long num)
    {
        return num != 0;
    }

    public static bool IsRequired(this double num)
    {
        return num != 0;
    }

    public static bool IsRequired(this Decimal num)
    {
        return num != 0;
    }

    public static bool IsRequired(this DateTime date)
    {
        return date != DateTime.MinValue;
    }

    #endregion


    #region String Lengths

    public static bool IsLengthLessThanOrEqual(this String str, int length)
    {
        return str.Length <= length;
    }

    public static bool IsRequiredWithLengthLessThanOrEqual(this String str, int length)
    {
        return !str.IsNullOrTrimEmpty() && (str.Length <= length);
    }

    public static bool IsRequired300LenNoSpecial(this String str)
    {
        return !str.IsNullOrTrimEmpty() &&
            str.RegexMatch(@"^[- \r\n\\\.!:*,@$%&""?\(\)\w']{1,300}$",
                RegexOptions.Multiline) == str;
    }

    #endregion

}

Si mi código es desordenado, así que es porque sólo he estado trabajando en este enfoque de validación de los últimos días. Necesito esta idea para cumplir una serie de requisitos:

  • necesito para apoyar la interfaz IDataErrorInfo así que mi capa MVC valida automáticamente
  • Tengo que ser capaz de soportar escenarios de validación complejas (el punto central de su pregunta, supongo): Quiero ser capaz de validar contra múltiples propiedades en el mismo objeto (. Es decir StartDate y finishDate); propiedades de diferentes objetos múltiples / / asociados como i tendrían en un gráfico de objetos; e incluso otras cosas que no he pensado todavía.
  • necesito para apoyar la idea de un error de aplicar a más de una propiedad
  • Como parte de mi TDD y el viaje DDD Quiero que mis objetos de dominio para describir más mi 'dominio' que mis métodos capa de servicio, por lo que poner estas condiciones complejas de los objetos del modelo (no DTO) parece lograr este

Este enfoque, creo que me va a conseguir lo que quiero, y tal vez también.

Me imagino que si salta a bordo conmigo en esto que estaríamos bastante 'por nosotros', pero podría valer la pena. Estaba leyendo acerca de la nuevas capacidades de validación en MVC 2 pero todavía no se ajusta a la lista de deseos anteriormente sin modificaciones personalizado.

Espero que esto ayude.

El S # arp Arquitectura tiene un identificador de método [DomainSignature] que se utiliza con el validador nivel de clase [HasUniqueDomainSignature] va a hacer el trabajo. Véase más abajo el código de ejemplo:

[HasUniqueDomainSignature]
public class User : Entity
{
    public User()
    {
    }

    public User(string login, string email) : this()
    {
        Login = login;
        Email = email;
    }

    [DomainSignature]
    [NotNullNotEmpty]
    public virtual string Login { get; set; }

    [DomainSignature]
    public virtual string Email { get; set; }

}

Tome una mirada más cercana a http://www.sharparchitecture.net/

tuve este mismo problema y después de tratar de encontrar una solución alternativa para días y días y días, terminé la fusión de mi DTO, DAL, y BL en una biblioteca. Mantuve la capa de presentación por separado. No estoy seguro si esto es una opción para usted o no. Para mí, pensé que mis posibilidades de constante cambio del almacén de datos eran muy leve, por lo que no era realmente necesario, el nivel separado.

También he implementado la Validación bloque de aplicación de Microsoft para todos mis validaciones DTO. Tienen un método de "validación automática" que le permite realizar validaciones complejas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top