Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc Asp.net mvc重建ViewModel的最佳实践是什么?_Asp.net Mvc - Fatal编程技术网

Asp.net mvc Asp.net mvc重建ViewModel的最佳实践是什么?

Asp.net mvc Asp.net mvc重建ViewModel的最佳实践是什么?,asp.net-mvc,Asp.net Mvc,在POST中,如果验证失败,并且在将ViewModel发送回具有模型状态错误的同一视图之前,是否为所有SelectList、ReadOnly字段等重新生成ViewModel? 现在,我有单独的方法用于第一次填充(对于GET Edit方法)/从域对象重建ViewModels,最佳做法是什么,这样我可以在向ViewModel添加新的readonly属性时不必更改两种方法 我的解决方案是:遵循这种模式 这里建议的模式如下: 在IModelBuilder实现中 Build(..) { var

在POST中,如果验证失败,并且在将ViewModel发送回具有模型状态错误的同一视图之前,是否为所有SelectList、ReadOnly字段等重新生成ViewModel? 现在,我有单独的方法用于第一次填充(对于GET Edit方法)/从域对象重建ViewModels,最佳做法是什么,这样我可以在向ViewModel添加新的readonly属性时不必更改两种方法

我的解决方案是:遵循这种模式

这里建议的模式如下: 在IModelBuilder实现中

Build(..)
{  
   var viewModel = new ViewModel();     
   // and Fill all Non-ReadOnly fields
   ...
   ...
   call CompleteViewModel(viewModel)     
}  

CompleteViewModel(ViewModel viewModel)
{
  //Fill all ReadOnly & SelectLists
  ...
}

我之所以使用此解决方案,是因为我不想在服务器上存储东西,以便跨HTTP请求检索。

最简单的解决方案是将viewModel传递给该方法,并考虑null

private MyViewModel BuildViewModel(MyViewModel model = null)
{
    model = model ?? new MyViewModel();
    model.ReadOnlyList = new .....
    .
    .
    return model;
}
对于创建:

 var model = BuildViewModel();
重建:

 model = buildViewModel(model);

我不会重建它,因为我不会呆在岗位上。我遵循POST-REDIRECT-GET模式,所以如果我使用POST HTTP方法发布到/User/Edit/1,我将使用GET重定向到/User/Edit/1

ModelState
被传输到
TempData
以跟踪重定向后的Get并在Get调用时可用。视图模型在GET调用时构建在一个位置。例如:

    [HttpPost]
    [ExportModelStateToTempData]
    public ActionResult Edit(int id, SomeVM postedModel)
    {
        if (ModelState.IsValid) {
            //do something with postedModel and then go back to list
            return RedirectToAction(ControllerActions.List);
        }

        //return back to edit, because there was an error
        return RedirectToAction(ControllerActions.Edit, new { id });
    }

    [ImportModelStateFromTempData]
    public ActionResult Edit(int id)
    {
        var model = //create model here
        return View(ControllerActions.Edit, model);
    }
这是导入/导出属性的代码
ModelState

public abstract class ModelStateTempDataTransferAttribute : ActionFilterAttribute
{
    protected static readonly string Key = typeof(ModelStateTempDataTransferAttribute).FullName;
}

public class ExportModelStateToTempDataAttribute : ModelStateTempDataTransferAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        //Only export when ModelState is not valid
        if (!filterContext.Controller.ViewData.ModelState.IsValid)
        {
            //Export if we are redirecting
            if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
            {
                filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

public class ImportModelStateFromTempDataAttribute : ModelStateTempDataTransferAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;

        if (modelState != null)
        {
            //Only Import if we are viewing
            if (filterContext.Result is ViewResult)
            {
                filterContext.Controller.ViewData.ModelState.Merge(modelState);
            }
            else
            {
                //Otherwise remove it.
                filterContext.Controller.TempData.Remove(Key);
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

我喜欢上面@LukLed的答案——看起来很有趣。如果你想要另一个选择,下面是我目前所做的

在我的服务层中,我有一个方法来构建我的视图模型。我在GET上调用它,并将视图模型返回到视图。在POST上,我从传入的ID构建模型,然后TryUpdateModel(model)。从那里,您可以做任何您喜欢的事情(保存、检查模型状态等)。使用此方法,您只有一个生成方法,并且在模型发生更改时(即,将来添加/删除属性等)只需更新一次

[HttpGet]
公共行动结果评估(int apaID)
{
var模型=this.apaService.buildassessfocussviewmodel(apaID);
返回此.View(model);
}
[HttpPost]
公共操作结果(int apaID,字符串按钮)
{
var模型=this.apaService.buildassessfocussviewmodel(apaID);
此.TryUpdateModel(model);
开关(按钮)
{
大小写按钮提交值。返回:
案例按钮SubmitValue。下一步:
案例按钮提交值。保存:
案例按钮SubmitValues.Save和Close:
{
尝试
{
this.apaService.SaveFocusResults(模型);
}
捕获(ModelStateException mse)
{
mse.ApplyTo(此.ModelState);
}
如果(!this.ModelState.IsValid)
{
这个.batherRorMessage(Resources.ErrorMsg\u WEB\u ValidationSummaryTitle);
返回此.View(model);
}
打破
}
违约:
抛出新的InvalidOperationException(string.Format(Resources.ErrorMsg_WEB_InvalidButton,button));
}
开关(按钮)
{
大小写按钮提交值。返回:
返回此.RedirectToActionFor(c=>c.EnterRecommendationsPartner(model.ApaID));
案例按钮SubmitValue。下一步:
返回此.RedirectToActionFor(c=>c.AssessCompetenciesPartner(model.ApaID));
案例按钮提交值。保存:
this.ShowSuccessMessage(Resources.Msg_WEB_NotifyBarSuccessGeneral);
返回此.RedirectToActionFor(c=>c.assessFocuss(model.ApaID));
案例按钮SubmitValues.Save和Close:
违约:
返回此.RedirectToActionFor(c=>c.CloseWindow());
}
}

但我认为这会覆盖用户所做的更改,除非我们检查只读字段的元数据(属性),选择列表并仅更新它们。@pjobs如果只更新只读字段,则不应覆盖任何用户输入!如果您传入一个填充了用户数据的模型,您将返回相同的模型,并且只有您覆盖的属性才会得到更新!好的,明白了,将viewmodel创建分为两个方法,一个用于填充只读属性,另一个用于非只读属性,在POST的情况下,按您所说的调用第一个方法。@Pu可以做到这一点。。。但我想说的是,这种方法对两种情况都有好处。。。它不会覆盖非只读属性,当你向它传递一个模型时,它只会填充只读属性并返回传入的同一个模型。我想当我说CreateNew/Rebuild时,我可能把你弄糊涂了,这里我说的CreateNew是指为Edit(GET)方法填充ViewModel。这很有趣,我知道这会转移错误以获取呼叫,但这会转移用户更改吗?@pjobs:是的。它也传递表单值。ModelState包含表单值。两年后,这仍然很棒。把这个放在我的项目里。@Josh:是的。我每天都在MVC项目中使用它。谢谢!这是非常有用的!
[HttpGet]
public ActionResult AssessFocuses(int apaID)
{
    var model = this.apaService.BuildAssessFocusesViewModel(apaID);
    return this.View(model);
}

[HttpPost]
public ActionResult AssessFocuses(int apaID, string button)
{
    var model = this.apaService.BuildAssessFocusesViewModel(apaID);
    this.TryUpdateModel(model);

    switch (button)
    {
        case ButtonSubmitValues.Back:
        case ButtonSubmitValues.Next:
        case ButtonSubmitValues.Save:
        case ButtonSubmitValues.SaveAndClose:
            {
                try
                {
                    this.apaService.SaveFocusResults(model);
                }
                catch (ModelStateException<AssessFocusesViewModel> mse)
                {
                    mse.ApplyTo(this.ModelState);
                }

                if (!this.ModelState.IsValid)
                {
                    this.ShowErrorMessage(Resources.ErrorMsg_WEB_ValidationSummaryTitle);
                    return this.View(model);
                }

                break;
            }

        default:
            throw new InvalidOperationException(string.Format(Resources.ErrorMsg_WEB_InvalidButton, button));
    }

    switch (button)
    {
        case ButtonSubmitValues.Back:
            return this.RedirectToActionFor<APAController>(c => c.EnterRecommendationsPartner(model.ApaID));

        case ButtonSubmitValues.Next:
            return this.RedirectToActionFor<APAController>(c => c.AssessCompetenciesPartner(model.ApaID));

        case ButtonSubmitValues.Save:
            this.ShowSuccessMessage(Resources.Msg_WEB_NotifyBarSuccessGeneral);
            return this.RedirectToActionFor<APAController>(c => c.AssessFocuses(model.ApaID));

        case ButtonSubmitValues.SaveAndClose:
        default: 
            return this.RedirectToActionFor<UtilityController>(c => c.CloseWindow());
    }
}