2012-10-29 4 views
6

Sto lavorando a un progetto scritto su mvc 4 che ha ottenuto diverse istanze di comportamento simile a una procedura guidata: una catena di poche visualizzazioni che passa lo stesso modello riempito a metà. A partire dalla seconda vista i controlli sono inizialmente mostrati come non validi (che è logico - modello, passati al metodo controller ha proprietà corrispondenti vuote). Attualmente viene impiegata la soluzione ModelState.Clear(); , ma inserirla in ogni metodo con il modello come argomento sembra brutta. Stessa cosa con approccio trovato qui Disable Model Validation in Asp.Net MVCCome disabilitare la convalida del modello MVC 4?

ModelBinders.Binders[typeof(MyModelType)] = new NonValidatingModelBinder(); 

progetto ha troppi (oltre 100) classi del modello per registrare ogni uno manualmente.

C'è un modo più semplice (forse inserire .config) che disattiva completamente la validazione del modello?

+3

Personalmente, penso che mi piacerebbe usare un ViewModel diverso per ogni passaggio della procedura guidata. Questo ti permetterebbe di usare la validazione dove ne hai bisogno (ad esempio sui valori del passaggio della procedura guidata corrente!). –

risposta

8

Non so che questo potrebbe funzionare, ma avete provato questo (codice di bootstrap o global.asax)

ModelValidatorProviders.Providers.Clear(); 
+0

L'ho controllato. Questo codice funziona. Nel mio progetto non posso usarlo perché i validatori creati da 'DataAnnotationsModelValidatorProvider' dalla raccolta cancellata sono stati utilizzati per ottenere ErrorMessages per i validatori lato client (invece di" * "predefinito). Ma questa è la risposta più semplice alla mia domanda. – user1782982

+0

Questo non funziona per me, e non capisco perché –

2

Non so tutte le opzioni in web.config o qualcosa del genere. Ma è possibile utilizzare questo:

Assembly.GetExecutingAssembly() 
    .GetTypes() 
    .Where(t => t.IsClass && t.Namespace == "Your.Name.Space") 
    .ToList() 
    .ForEach(t => ModelBinders.Binders[t] = new NonValidatingModelBinder()); 

O

typeof(MyModelType) 
    .Assembly 
    .GetTypes() 
    .Where(t => t.IsClass && t.Namespace == "Your.Name.Space") 
    .ToList() 
    .ForEach(t => ModelBinders.Binders[t] = new NonValidatingModelBinder()); 

o rimuovere la parte && t.Namespace == "Your.Name.Space" quindi si aggiungerà tutte le classi nella vostra assemblea per NonValidatingModelBinder.

Non dimenticare di aggiungere using System.Linq;

4

Lo so che non è così davvero rispondere alla tua domanda, ma solo per espandere il mio commento: -

Sembra che tu hai qualcosa di simile: -

public class MyModel 
{ 
    [Required] 
    public string Foo { get; set; } // Populated in step 1 
    [Required] 
    public string Bar { get; set; } // Populated in step 2 
} 

Si è verificato un problema durante il passaggio 1 di POST perché l'utente non ha ancora inserito un valore per Bar, quindi c'è un ModelStateError.

La mia soluzione preferita, piuttosto che cercare di pasticciare con la validazione del modello di persistenza, sarebbe quella di separare la vostra vista implementazione dalla vostra implementazione Modello con una ViewModel per ogni passaggio della procedura guidata, ad esempio: -

public class MyModel 
{ 
    [Required] 
    public string Foo { get; set; } 
    [Required] 
    public string Bar { get; set; } 
} 

public class StepOneModel 
{ 
    [Required] 
    public string Foo { get; set; } 
} 

public class StepTwoModel 
{ 
    // This really depends on the behaviour you want. 
    // In this example, the model isn't persisted until 
    // the last step, but you could equally well persist 
    // the partial model server-side and just include a 
    // key in subsequent wizard steps. 
    [Required] 
    public StepOneModel StepOne { get; set; } 

    [Required] 
    public string Bar { get; set; } 
} 

Le vostre azioni del controller simile a: -

public ActionResult StepOne() 
{ 
    return View(new StepOneViewModel()); 
} 
[HttpPost] 
public ActionResult StepOne(StepOneViewModel model) 
{ 
    if(ModelState.IsValid) 
    { 
    var stepTwoModel = new StepTwoViewModel() 
    { 
     StepOne = model 
    }; 

    // Again, there's a bunch of different ways 
    // you can handle flow between steps, just 
    // doing it simply here to give an example 
    return View("StepTwo", model); 
    } 

    return View(model); 
} 
[HttpPost] 
public ActionResult StepTwo(StepTwoViewModel model) 
{ 
    if (ModelState.IsValid) 
    { 
    // You could also add a method to the final ViewModel 
    // to do this mapping, or use something like AutoMapper 
    MyModel model = new MyModel() 
    { 
     Foo = model.StepOne.Foo 
     Bar = model.Bar 
    }; 

    this.Context.MyModels.Add(model); 
    this.Context.SaveChanges(); 
    } 

    return View(model); 
} 

La vista StepOne sembra qualcosa di simile: -

@model StepOneModel 
@using (html.BeginForm()) { 
    @html.EditorFor(x => x.Foo); 
} 

La vista Steptwo sembra qualcosa di simile: -

@model StepTwoModel 
@using (html.BeginForm("StepTwo")) { 
    @html.HiddenFor(x => x.StepOne); 
    @html.EditorFor(x => x.Bar); 
} 

Il principale vantaggio rispetto ad appena spegnere validazione del modello è che si può mettere i requisiti di convalida per il passo attuale sul ViewModel - è possibile garantire che tutte le i valori del primo passaggio sono validi prima di procedere al passaggio due.

  • Se si desidera un approccio più riposante (dove il controller non si preoccupa che i dati proviene da una vista wizard-stile) un'altra soluzione popolare è quello di avvolgere ogni passo di un <div> lato client e usa javascript per nasconderli/mostrarli mentre l'utente avanza.

  • Se il modello deve essere persistente tra un passaggio e l'altro, è necessario pensare a ValidationAttributes sul modello e al loro significato. Se hai annotato User.DateOfBirth con Required, ma devi essere in grado di mantenerlo prima che venga popolato, in effetti User.DateOfBirthnon è richiesto (ad esempio EF CodeFirst non può rendere la colonna NOT NULL perché è necessario essere in grado di mantenere valori nulli nel frattempo). Dovrai eseguire alcune convalide condizionali (ad esempio IValidatableObject, MvcFoolproof, Fluent Validation) per convalidare il modello completo in un secondo momento.

+0

+1 iain - bel riassunto :) –

0
@{ 
HtmlHelper.ClientValidationEnabled = false; 
}