Hello, dear forum users!

I have a pretty simple question. There is a method in the controller that should return an ActionResult. The last lines of the method look like this:

List<int> list = (List<int>) Session["myList"]; return RedirectToAction("ListViewer", "ListManager", new { myList = list }); 

However, when you go to the ListViewer(List<int> myList) method ListViewer(List<int> myList) ListManager , the input parameter remains empty. That is, when RedirectToAction is executed, the value is lost, although I know for sure that I am transmitting a completed sheet, as seen in debugging. Please tell me what is wrong with this solution and how can I transfer a collection of elements?

    2 answers 2

    RedirectToAction is not a switch to another controller method. This is a return to the client (browser) of a new url, which leads to another Action. What you pass to the third parameter becomes part of this url.

    Your sheet is assigned to the returned link as a GET parameter. The link is given to the client side - the browser. The browser makes a new request for the link. The server is trying to get data from the incoming request for the myList parameter. And then a couple of problems arise.

    • ASP.NET MVC does not know how to convert lists and generally complicated things into url parameters. It is limited to calling ToString. Therefore, the client is given a not very useful link like

       /ListManager/ListViewer?myList=System.Collections.Generic.List%601%5BSystem.Int32%5D 
    • When processing a request, ASP.NET MVC can parse the List parameter. But only if each of the elements of the list comes in a separate GET parameter. With the names myList[0] ..., myList[1] . Well, or at least [0] , [1] . Those. he is waiting for a reference

       /ListManager/ListViewer?%5B0%5D=1&%5B1%5D=2&%5B2%5D=3 

    To generate it, your code should look something like this:

     var values = new RouteValueDictionary( list .Select((item, index) => new { item, index }) .ToDictionary( key => string.Format("[{0}]", key.index), value => (object)value.item ) ); return RedirectToAction("ListViewer", "ListManager", values); 

    But in your case - these are all unnecessary crutches. There are two much simpler options:

    • Correct - to take out the general code from two actions in a separate method. Return from both your action and ListViewer the result of calling this method. And do not redirect the client back and forth, with the data in the address bar.
    • Slightly less correct is to redirect to ListViewer without parameters. Well, or with a parameter like fromSession = true . ListViewer is the same Action as the current. It can also get values ​​from a session in the same way. There is no need to transfer them as part of the url to the client side, and then back.
    • You can also use TempData - Ice2burn
    • @ Ice2burn yes, but TempData uses the session inside, and the TC has data in the session anyway - PashaPash
    • @PashaPash, thank you so much for such a wonderful answer !!!))) - neo
     return View("ListViewer", list); 
    • but in a different way? I just don’t want to duplicate all the values ​​for the ViewBag every time, and there are plenty of them. And if we return the "View", then they must be prescribed necessarily. And if we redirect to action, then it will calculate them. - neo
    • "ViewBag, but they are not enough." - it’s time to reconsider their use in the direction of using special presentation model classes - Oleg Sh
    • @ Oleg Sh, can you give any example of what you say in the form of code? - neo
    • use for example the class public class ZoneElementViewModel {public int ZoneID {get; set; } public string ZoneName {get; set; } public DateTime DateCreated {get; set; } public bool HasPdf {get; set; }} instead of ViewBag.ZoneName, ViewBag.DateCreated .... - Oleg Sh