如何将模型传递给具有其他参数的动作

Posted

技术标签:

【中文标题】如何将模型传递给具有其他参数的动作【英文标题】:How to pass model to an action which have other parameters 【发布时间】:2011-07-03 12:55:00 【问题描述】:

我的以下问题是,当我通过 DeleteEmployee 中的 catch 部分时,如何将 ModelStateErrors 发送给操作 Employee

   public ActionResult Employee(int ID, string Name)
    
        EmployeeListModel model = new EmployeeListModel (ID, projectName);
        return View(model);
    

 public ActionResult DeleteEmployee(Employee emp)
    

        try
        
            emp.Delete();
            return RedirectToAction("Employee", new  ID = emp.ID, Name = emp.Name );
        

        catch (Exception e)
        
            EmployeeListModel model = new EmployeeListModel (emp.ID, emp.Name);
            ModelState.AddModelError("Error", e.Message);
            return RedirectToAction("Employee", model);
        
    

With return View("Employee", model);我仍然无法将 ID 和名称作为参数发送。

【问题讨论】:

【参考方案1】:

使用TempDataModelState 持久化到多个控制器操作中。

MvcContrib 有一个执行此操作的操作过滤器。 Jeremy Skinner 在http://www.jeremyskinner.co.uk/2008/10/18/storing-modelstate-in-tempdata-with-aspnet-mvc/ 上写了代码和一篇关于它的博客文章。那里的源链接已损坏,所以我在下面发布了代码。

ModelStateToTempDataAttribute Source Code

/// <summary>
/// When a RedirectToRouteResult is returned from an action, anything in the ViewData.ModelState dictionary will be copied into TempData.
/// When a ViewResultBase is returned from an action, any ModelState entries that were previously copied to TempData will be copied back to the ModelState dictionary.
/// </summary>
public class ModelStateToTempDataAttribute : ActionFilterAttribute

    public const string TempDataKey = "__MvcContrib_ValidationFailures__";

    /// <summary>
    /// When a RedirectToRouteResult is returned from an action, anything in the ViewData.ModelState dictionary will be copied into TempData.
    /// When a ViewResultBase is returned from an action, any ModelState entries that were previously copied to TempData will be copied back to the ModelState dictionary.
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    
        var modelState = filterContext.Controller.ViewData.ModelState;

        var controller = filterContext.Controller;

        if(filterContext.Result is ViewResultBase)
        
            //If there are failures in tempdata, copy them to the modelstate
            CopyTempDataToModelState(controller.ViewData.ModelState, controller.TempData);
            return;
        

        //If we're redirecting and there are errors, put them in tempdata instead (so they can later be copied back to modelstate)
        if((filterContext.Result is RedirectToRouteResult || filterContext.Result is RedirectResult) && !modelState.IsValid)
        
            CopyModelStateToTempData(controller.ViewData.ModelState, controller.TempData);
        
    

    private void CopyTempDataToModelState(ModelStateDictionary modelState, TempDataDictionary tempData)
    
        if(!tempData.ContainsKey(TempDataKey)) return;

        var fromTempData = tempData[TempDataKey] as ModelStateDictionary;
        if(fromTempData == null) return;

        foreach(var pair in fromTempData)
        
            if (modelState.ContainsKey(pair.Key))
            
                modelState[pair.Key].Value = pair.Value.Value;

                foreach(var error in pair.Value.Errors)
                
                    modelState[pair.Key].Errors.Add(error);
                
            
            else
            
                modelState.Add(pair.Key, pair.Value);
            
        
    

    private static void CopyModelStateToTempData(ModelStateDictionary modelState, TempDataDictionary tempData)
    
        tempData[TempDataKey] = modelState;
    

这里有一些类似的帖子

ASP.NET MVC - How to Preserve ModelState Errors Across RedirectToAction? How can I maintain ModelState with RedirectToAction?

【讨论】:

【参考方案2】:

从视图来看,模型状态字典是 ViewDataDictionary 的一部分,因此请尝试通过 viewdata 访问它,至少在 MVC 3 中是这样(相信在旧版本中也是如此)。您不需要通过模型传递它,而是通过这种方式访问​​它。

但是,我不知道如果您进行重定向,模型状态错误是否会保留;您可能想直接返回响应:

return View("Employee", model);

HTH。

【讨论】:

如何在返回部分传递 ID 和 name 的值?【参考方案3】:

ID 和 Name 的值被封装在您传递给“View”ActionResult 的 EmployeeListModel 中:

型号.ID 型号.名称

注意,@Brian 是正确的,因为您需要使用“View”ActionResult 而不是“RedirectToAction”ActionResult,否则模型状态错误将会丢失。另一种方法是将模型状态存储在 TempData 中,它实际上是会话对象的特殊包装器。如果您需要确保正确更新您的网址,则需要使用“RedirectToAction”ActionResult 之类的东西...

【讨论】:

虽然 ID 和 Name 的值将存储在模型中,但我需要将这些值作为参数传递,否则 EmployeeListModel model = new EmployeeListModel (ID, projectName) in Employee 没有所需的值,因此搜索不会带来正确的值! 听起来你真的很想使用 RedirectToAction。如果是这样的话,那么看看这个接受的答案 - ***.com/questions/1936/…【参考方案4】:

将 ModelState 存储在 TempData 中:

TempData["ModelState"] = ModelState;

然后使用动作过滤器合并 ModelState,例如:

protected override void OnActionExecuted(ActionExecutedContext context)

    filterContext.Controller.ViewData.ModelState.Merge((ModelStateDictionary)TempData["ModelState"]);

希望这会有所帮助。

【讨论】:

【参考方案5】:

试试下面的代码 //作为最佳实践,始终使用 Viewmodel,例如employeeViewMode 并将您的视图强输入到 viewmodel 公共类 EmployeviewModel 公共 int id; 公共字符串名称; 公共字符串错误消息; 公共 ActionResult Employee(int ID) EmployeeListModel model = new EmployeeListModel(ID, projectName); EmployeviewModel vm = new EmployeviewModel(); vm.id = 模型.id; vm.name = 型号.name; if (TempData.Keys.Count() > 0) vm.errormessage = TempData["errormessage"]; 返回视图(vm);

    public ActionResult DeleteEmployee(Employee emp)
    
        try
        
            emp.Delete();
            return RedirectToAction("Employee", new  ID = emp.ID, Name = emp.Name );
        

        catch (Exception e)
        
            //use TempData to store error message
            TempData["ErrorMessage"] = e.message;
            return RedirectToAction("Employee", emp.ID);
        
    

【讨论】:

以上是关于如何将模型传递给具有其他参数的动作的主要内容,如果未能解决你的问题,请参考以下文章

如何在每个控制器中不重复代码的情况下将模型传递给我的主视图模板?

为啥从 AOP 传递到具有其他参数的控制器的模型的所有属性都是空的

如何绕过将数据模型传递给片段参数以避免事务太大异常?

如何从模型实例(具有来自 api 的值)传递数据并将其提供给 Text() 小部件

如何将文件中的其他参数从 Angular 传递给 ASP.NET Core 控制器?

ASP.NET MVC我想重定向到另一个将我的模型传递给它的动作,以获得正确的URL