【问题标题】:Populate ViewModel by a wizard approach通过向导方法填充 ViewModel
【发布时间】:2015-07-31 10:50:31
【问题描述】:

我找到了如何在 ASP MVC 中创建向导的绝佳答案。
multi-step registration process issues in asp.net mvc (splitted viewmodels, single model)

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

假设在第 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);
}

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

【问题讨论】:

    标签: c# asp.net asp.net-mvc asp.net-mvc-4


    【解决方案1】:

    从控制器填充。总是。您永远不应该在视图模型或更糟的实体中与您的上下文进行交互。如果您想抽象数据库工作,请将其移动到存储库或服务中,然后让您的控制器对其调用方法。

    【讨论】:

    • 谢谢,我会把它添加到控制器中。下一个问题是在哪里。我有一个初始化向导的控制器和一个处理 POST 请求的控制器。如果我将它添加到初始化程序中,数据将遵循所有步骤,这是一种好习惯吗?或者我应该尝试在 POST 控制器中添加一些检查,以找出我在哪一步并将数据注入正确的视图模型?
    • 如果“initializer”是指“constructor”,那么不,你不想在那里这样做。每个请求都会实例化和处理控制器。如果您需要在请求之间共享数据,则需要每次都发布所有内容或将其添加到 TempData 之类的内容中。
    【解决方案2】:

    我最后得到了这个。 但我真的很想得到一些关于这种方法的反馈。 例如,我怎样才能将这个控制器乱七八糟地移到自定义模型绑定器中?

    片段

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

    【讨论】:

      猜你喜欢
      • 2015-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多