learning
learning

Reputation: 11725

How to pass model to an action which have other parameters

My problem with the following is how do I send the ModelStateErrors to the action Employee, when I go through the catch part in DeleteEmployee

   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); I a still not able to send the ID and Name as parameter.

Upvotes: 2

Views: 5840

Answers (5)

smartcaveman
smartcaveman

Reputation: 42246

Use TempData to persist the ModelState across multiple controller actions.

MvcContrib has an action filter that does this. Jeremy Skinner wrote the code and a blog post about it at http://www.jeremyskinner.co.uk/2008/10/18/storing-modelstate-in-tempdata-with-aspnet-mvc/. The link there for the source is broken, so I posted the code below.

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

Here are some similar posts

Upvotes: 5

swapneel
swapneel

Reputation: 3061

Try below code //as a best practise always use Viewmodel e.g. employeeViewMode and strongly type your view to viewmodel public class EmployeviewModel { public int id; public string name; public string errormessage; } public ActionResult Employee(int ID) { EmployeeListModel model = new EmployeeListModel(ID, projectName); EmployeviewModel vm = new EmployeviewModel(); vm.id = model.id; vm.name = model.name; if (TempData.Keys.Count() > 0) { vm.errormessage = TempData["errormessage"]; } return View(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);
        }
    }

Upvotes: 1

Kalman Speier
Kalman Speier

Reputation: 1947

Store the ModelState in TempData:

TempData["ModelState"] = ModelState;

Then merge the ModelState using an action filter for example:

protected override void OnActionExecuted(ActionExecutedContext context)
{
    filterContext.Controller.ViewData.ModelState.Merge((ModelStateDictionary)TempData["ModelState"]);
}

Hope this helps.

Upvotes: 1

Bermo
Bermo

Reputation: 4931

The values for ID and Name are being sent wrapped up in the EmployeeListModel you pass to the "View" ActionResult:

  • Model.ID
  • Model.Name

Note, @Brian is correct in that you'll need to use the "View" ActionResult rather than "RedirectToAction" ActionResult otherwise the modelstate errors would be lost. The alternative is to store your modelstate in TempData which is really a special wrapper around the session object. You would need to use something like the "RedirectToAction" ActionResult if you need to ensure your url's are updated properly ...

Upvotes: 1

Brian Mains
Brian Mains

Reputation: 50728

From the view, the model state dictionary is a part of the ViewDataDictionary, so try accessing it through viewdata, at least in MVC 3 (believe that way in older versions as well). You don't need to pass it through the model, but instead access it this way.

However, i don't know if model state errors are retained if you do a redirect; you may want to return the response directly instead:

return View("Employee", model);

HTH.

Upvotes: 1

Related Questions