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.DateOfBirth
non è 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.
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!). –