通过向导方法填充ViewModel

本文关键字:填充 ViewModel 方法 向导 | 更新日期: 2023-09-27 18:05:47

我找到了如何在ASP MVC中做向导的好答案。
asp.net MVC中的多步骤注册过程问题(拆分视图模型,单个模型)

我只有一个与此相关的问题。将数据填充到视图模型中的最佳实践是什么?

假设在步骤2中,我需要向用户显示一个数据列表。列表数据来自数据库。然后我应该继续创建视图模型的构造函数,还是应该在控制器中填充它?

这是我的代码现在的样子。

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

那么我的问题是,我将在哪里填充步骤2的列表?我的第一个想法是在Step2视图模型中有一个构造函数。第二个想法是在控制器中添加一些逻辑,找出我所处的步骤,并从那里填充它。但这一切听起来有点糟糕。

通过向导方法填充ViewModel

从控制器填充。总是这样。永远不要在视图模型或更糟糕的实体中与上下文进行交互。如果你想抽象数据库工作,把它移到一个存储库或服务,然后让你的控制器调用一个方法。

我在最后结束了这个。但我真的很想得到一些关于这种方法的反馈。例如,我如何将这个混乱的控制器移动到自定义模型绑定器中?

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