我找到了如何在ASP MVC中执行向导的很好的答案 multi-step registration process issues in asp.net mvc (splitted viewmodels, single model)
我只有一个与此相关的问题。将数据填充到视图模型中的最佳做法是什么?
让我们说在第2步中,我需要向用户显示数据列表。列表数据来自DB。然后我会继续为视图模型创建一个构造函数,还是应该在控制器中填充它?
这就是我的代码现在的样子。
模型
[Serializable]
public class Step1ViewModel : IStepViewModel
{
public bool MyProperty { get; set; }
}
[Serializable]
public class Step2ViewModel : IStepViewModel
{
// This needs to be populated with data, I need to display it in a list
public List<string> MyList { get; set; }
}
[Serializable]
public class Step3ViewModel : IStepViewModel
{
public bool MyProperty { get; set; }
}
[Serializable]
public class PublishViewModel
{
public int CurrentStepIndex { get; set; }
public IList<IStepViewModel> Steps { get; set; }
public void Initialize()
{
Steps = typeof(IStepViewModel)
.Assembly
.GetTypes()
.Where(t => !t.IsAbstract && typeof(IStepViewModel).IsAssignableFrom(t))
.Select(t => (IStepViewModel)Activator.CreateInstance(t))
.ToList();
}
public class PublishViewModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var stepTypeValue = bindingContext.ValueProvider.GetValue("StepType");
var stepType = Type.GetType((string)stepTypeValue.ConvertTo(typeof(string)), true);
var step = Activator.CreateInstance(stepType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => step, stepType);
return step;
}
}
public interface IStepViewModel
{
}
控制器
public ActionResult Publish(int? id)
{
var publish = new PublishViewModel();
publish.Initialize();
return View(publish);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Publish([Deserialize] PublishViewModel publish, IStepViewModel step)
{
publish.Steps[publish.CurrentStepIndex] = step;
if (ModelState.IsValid)
{
if (!string.IsNullOrEmpty(Request["next"]))
{
publish.CurrentStepIndex++;
}
else if (!string.IsNullOrEmpty(Request["prev"]))
{
publish.CurrentStepIndex--;
}
else
{
// TODO: we have finished: all the step partial
// view models have passed validation => map them
// back to the domain model and do some processing with
// the results
return Content("thanks for filling this form", "text/plain");
}
}
else if (!string.IsNullOrEmpty(Request["prev"]))
{
// Even if validation failed we allow the user to
// navigate to previous steps
publish.CurrentStepIndex--;
}
return View(publish);
}
所以我的问题是,我在哪里填写Step2的列表? 我的第一个想法是在Step2视图模型中有一个构造函数。第二个想法是让控制器中有一些逻辑找出哪个步骤,并从那里填充它。但这听起来有点不好。
答案 0 :(得分:2)
从控制器填充。总是。您永远不应该在视图模型内部或者更糟的是与实体进行交互。如果要抽象数据库工作,请将其移动到存储库或服务,然后让控制器调用该方法。
答案 1 :(得分:0)
我最后结束了这一切。 但我真的很想得到一些关于这种方法的反馈。 例如,我怎么能将这个控制器混乱移动到自定义模型绑定器中?
<强>段强>
if (publish.Steps[publish.CurrentStepIndex].GetType() == typeof(Step1ViewModel))
{
var model = publish.Steps[publish.CurrentStepIndex] as Step1ViewModel;
// Do some magic
}
完整代码
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Publish([Deserialize] PublishViewModel publish, IStepViewModel step)
{
publish.Steps[publish.CurrentStepIndex] = step;
if (ModelState.IsValid)
{
if (!string.IsNullOrEmpty(Request["next"]))
publish.CurrentStepIndex++;
else if (!string.IsNullOrEmpty(Request["prev"]))
publish.CurrentStepIndex--;
}
else if (!string.IsNullOrEmpty(Request["prev"]))
{
publish.CurrentStepIndex--;
}
if (publish.Steps[publish.CurrentStepIndex].GetType() == typeof(Step1ViewModel))
{
var model = publish.Steps[publish.CurrentStepIndex] as Step1ViewModel;
// Do some magic
}
else if (publish.Steps[publish.CurrentStepIndex].GetType() == typeof(Step2ViewModel))
{
var model = publish.Steps[publish.CurrentStepIndex] as Step2ViewModel;
// Do some magic
}
return View(publish);
}