Domanda

Descrizione

La mia soluzione ha questi progetti:

  • DAL = Modificato Entity Framework
  • DTO oggetti di trasferimento = dati che sono in grado di convalidare se stessi
  • BL = Affari livello di servizi
  • Web = presentazione applicazione Asp.net MVC

DAL, BL e WEB ogni riferimento DTO che è grande.
Il processo di solito esegue in questo modo:

  1. Una richiesta web è fatto per il WEB
  2. WEB ottiene DTOS postato
    • DTOs ottenere automagically convalidati tramite personalizzato ActionFilter
    • errori di validazione sono auto-raccolti
  3. (convalida è OK) WEB chiama in BL forniscono DTOs
  4. BL mette in DAL utilizzando DTOs (può o farli passare attraverso o semplicemente usarli)

problema DTO Convalida poi ...

I miei DTOs sono in grado di convalidare se stessi sulla base di un proprio stato (valori proprieta). Ma in questo momento sto presentato con un problema quando non è questo il caso. Ne ho bisogno per validare utilizzando BL (e conseguentemente DAL).

Il mio esempio di vita reale : i registri utente e WEB ottiene un DTO utente che viene convalidato. La parte problematica è la convalida username. La sua unicità deve essere controllato contro archivio dati.
Come faccio a fare questo?

Non c'è informazioni aggiuntive che tutti DTOs implementano un'interfaccia (es. User DTO implementa IUser) per scopi di CIO e TDD. Entrambi sono parte del progetto DTO .

tentativi Impossible

  1. Non posso riferire BL in DTO perché avrò riferimento circolare.
    Compilation error
  2. Non posso creare un ulteriore progetto DTO.Val che fare riferimento alle classi parziali DTO e implementare la loro validazione lì (che avevano riferimento BL + DTO).
    Partial classes can't span assemblies.

possibili tentativi

  1. Crea un ActionFilter speciale che convalidare oggetto contro le condizioni esterne. Questo sarebbe stato creato all'interno di progetto WEB di vedere così DTO e BL che sarebbe stato utilizzato qui.
  2. Mettere in DTOs BL e mantenere interfacce DTO come DTOs effettivi a cui fanno riferimento altri progetti e refactoring tutto il codice per utilizzare le interfacce, invece di classi concrete.
  3. non gestiscono la convalida dipendente esterno e lasciare dipendenze esterne generano un'eccezione - probabilmente il peggior soluzione a questo problema

Cosa suggeriresti?

È stato utile?

Soluzione 4

risultante soluzione

Ho finito per usare filtro azione di controllo che è stato in grado di convalidare oggetto contro fattori esterni che non possono essere ottenuti con l'oggetto stesso.

ho creato il filtro che prende il nome del parametro azione per controllare e tipo di validatore che convaliderà quel parametro particolare. Naturalmente questo validatore deve attuare alcune interfaccia per rendere il tutto riutilizzabile.

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

validatore ha bisogno di implementare questa semplice interfaccia

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

Si tratta di una soluzione semplice ed efficace ad un problema apparentemente complesso.

Altri suggerimenti

Vorrei suggerire un esperimento che ho solo potuto provare in anteprima per l'ultima settimana o giù di lì.

In base a questa ispirazione sto creando DTOs che convalidano un po 'diverso per che dell'approccio DataAnnotations. Esempio DTO:

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()
        });
    }
}

Questa potrebbe apparire più lavoro che DataAnnotations e bene, questo è coz lo è, ma non è enorme. Penso che sia più presentabile nella classe (ho alcune classi DTO davvero brutto ora con attributi DataAnnotations - non si può nemmeno vedere le proprietà più). E il potere dei delegati anonimi in questa applicazione è quasi libro degno (in modo che io sto scoprendo).

Classe di 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
}

funzioni ValidationRule e la mia validazione:

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

}

Se il mio codice è ben disordinato che è perché ho solo lavorato su questo approccio di convalida per gli ultimi giorni. Ho bisogno di questo idea di soddisfare alcuni requisiti:

  • Ho bisogno di supportare l'interfaccia IDataErrorInfo quindi il mio strato di MVC convalida automaticamente
  • Ho bisogno di essere in grado di supportare scenari di validazione complessi (il punto della tua domanda credo): Voglio essere in grado di convalidare contro proprietà multiple sullo stesso oggetto (. Es StartDate e FinishDate); oggetti di diversi / più oggetti / associati come avrei in un oggetto grafico; e anche altre cose che non ho ancora pensato.
  • ho bisogno di sostenere l'idea di un errore applicare a più di una proprietà
  • Come parte del mio TDD e viaggio DDD voglio che il mio dominio oggetti per descrivere più la mia 'dominio' che i miei metodi di livello di servizio, in modo da mettere queste condizioni complesse negli oggetti del modello (non DTOs) sembra per raggiungere questo obiettivo

Questo approccio penso che otterrà me quello che voglio, e forse pure.

Mi immagino se si salta a bordo con me su questo che saremmo stati abbastanza 'da noi stessi' ma potrebbe essere valsa la pena. Stavo leggendo la nuove funzionalità di validazione in MVC 2 ma ancora non soddisfa la lista dei desideri di cui sopra senza modifiche personalizzato.

Spero che questo aiuti.

L'S # arp Architettura ha un metodo [DomainSignature] identificatore che utilizzato con il validatore livello di classe [HasUniqueDomainSignature] farà il lavoro. Vedere il codice di esempio riportato di seguito:

[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; }

}

Date un'occhiata più da vicino a http://www.sharparchitecture.net/

Ho avuto questo problema esattamente lo stesso e dopo aver tentato di trovare un lavoro in giro per giorni e giorni e giorni, ho finito per la fusione mio DTO, DAL, e BL in una libreria. Ho mantenuto la mia livello di presentazione separata. Non sono sicuro se questo è un'opzione per voi oppure no. Per quanto mi riguarda, ho pensato che le mie possibilità di continua evoluzione l'archivio dati erano molto leggero, e quindi il livello separato non era davvero necessario.

Inoltre ho implementato Microsoft Validation Application Block per tutti i miei convalide DTO. Hanno un metodo di "Self convalida" che consente di eseguire le convalide complesse.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top