15

Below, in CreateTest, uponsuccessful, I want to redirect to Tests from CreateTest.

I want to do something like the following:

    public ActionResult Tests(int ID, string projectName)
    {
        TestModel model = new TestModel (ID, projectName);
        return View(model);
    }

 [HttpPost]
    public ActionResult CreateTest(TestModel model)
    {
        try
        {
            return RedirectToAction("Tests");
        }
        catch (Exception e)
        {
            ModelState.AddModelError("Error", e.Message);
            return View(model);
        }
    }
Marc Climent
  • 9,434
  • 2
  • 50
  • 55
learning
  • 11,415
  • 35
  • 87
  • 154

3 Answers3

39

You might need to provide the arguments when redirecting:

return RedirectToAction("Tests", new { 
   ID = model.ID, 
   projectName = model.ProjectName 
});

and the url you will be redirecting to will now look something like this:

/Foo/Tests?ID=123&projectName=abc

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Thanks, but how to return error messages as well? public ActionResult CreateTest(TestModel model) { try { return RedirectToAction("Tests"); } catch (Exception e) { ModelState.AddModelError("Error", e.Message); return View(Tests); } } – learning Feb 24 '11 at 09:07
  • @user281180, you could pass them in the query string as well: `new { ID = model.ID, projectName = model.ProjectName, errorMessage = "Some error message" }`. But from what I can see in case of an error you are not redirecting you are simply rendering the view which is the correct way of doing it, so you can directly access the error message inside the view as it is added to the model state. – Darin Dimitrov Feb 24 '11 at 09:10
  • @Darin It`s not working, i`m having the error message : The model item passed into the dictionary is of type '<>f__AnonymousType1`2[System.Int32,System.String]', but this dictionary requires a model item of type 'MvcUI.Models.TestModel'. – learning Feb 24 '11 at 09:15
  • when using return RedirectToAction("Tests", new { ID = model.ID, projectName = model.ProjectName }); – learning Feb 24 '11 at 09:42
  • @Darin I am also having the error message: The parameters dictionary contains a null entry for parameter 'ID' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Tests(Int32, System.String)' in 'MvcUI.Controllers.ProjectController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter. Parameter name: parameters – learning Feb 24 '11 at 10:07
  • 1
    @user281180, I don't know where is this anonymous type coming from. Try hardcoding the values first: `return RedirectToAction("Tests", new { ID = "123", projectName = "abc" });`. Make sure that the ID parameter is not empty because in your target controller action it is not nullable. You could make it nullable integer if necessary. – Darin Dimitrov Feb 24 '11 at 10:14
  • @Darin The piece of code public ActionResult CreateTest(TestModel model) { try { return RedirectToAction("Tests"); } catch (Exception e) { ModelState.AddModelError("Error", e.Message); return View(Tests); } } in`t working as well. – learning Feb 24 '11 at 10:17
  • @Darin, i`ts with the above code that I am having the eror message : he model item passed into the dictionary is of type '<>f__AnonymousType1`2[System.Int32,System.String]', but this dictionary requires a model item of type 'MvcUI.Models.TestModel'. – learning Feb 24 '11 at 10:31
1

I know this is a bit old but...

What I've done in the past is have a "MessageArea" class exposed as a property on my base controller that all my controllers ultimately inherit from. The property actually stores the class instance in TempData. The MessageArea has a method to Add() which takes a string message and an enum Type (e.g. Success, Error, Warning, Information).

I then have a partial that renders whatever messages are in MessageArea with appropriate styling according to the type of the message.

I have a HTMLHelper extension method RenderMessageArea() so in any view I can simple say @Html.RenderMessageArea(), the method and partial take care of nulls and nothing is output if there are no messages.

Because data stored in TempData only survives 1 request it is ideal for cases where you want your action to redirect but have 1 or more messages shown on the destination page, e.g. an error, not authorised page etc... Or if you add an item but then return to the index list page.

Obviously you could implement something similar to pass other data. Ultimately I'd say this is a better solution to the original question than the accepted answer.

EDIT, EXAMPLE:

public class MessageAreaModel {
   public MessageAreaModel() {
       Messages = new List<Message>();
   }

   public List<Message> Messages { get; private set; }

   public static void AddMessage(string text, MessageIcon icon, TempDatadictionary tempData) {
       AddMessage(new Message(icon, text), tempData);
   }

   public static void AddMessage(Message message, TempDataDictionary tempData) {
       var msgArea = GetAreaModelOrNew(tempData);
       msgArea.Messages.Add(message);
       tempData[TempDataKey] = msgArea;
   }

   private static MessageAreaModel GetAreaModelOrNew(TempDataDictionary tempData) {
       return tempData[TempDataKey] as MessageAreaModel ?? new MessageAreaModel();
   }

The above class can then be used to add messages from your UI layer used by the controllers.

Then add an HtmlHelper extension like so:

public static void RenderMessageArea(this HtmlHelper html) {
    html.RenderPartial("MessageArea", 
        (MessageAreaModel)html.ViewContext.TempData[MessageAreaModel.TempDataKey] ?? MessageAreaModel.Empty);
    html.ViewContext.TempData.Remove(MessageAreaModel.TempDataKey);
}

The above is not fully completed code there are various bells and whistles I've left out but you get the impression.

Peter
  • 797
  • 11
  • 35
0

Make the int nullable:

public ActionResult Tests(int? ID, string projectName){
    //...
}
Koopakiller
  • 2,838
  • 3
  • 32
  • 47
Rob
  • 10,004
  • 5
  • 61
  • 91