Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Storing objects (non-string things) in TempDataDictionary does not round trip correctly #2276

Closed
pranavkm opened this issue Mar 26, 2015 · 16 comments
Assignees
Milestone

Comments

@pranavkm
Copy link
Contributor

Scenario

public class FeedbackController : Controller
{
    private const string _userKey = "user-data";

    [HttpPost]
    public IActionResult SubmitApplication(string name, int age)
    {
        // Do db stuff
        var user = new User { Id = 100, Name = name, Age = age };
        TempData[_userKey] = user;
        return RedirectToAction("WelcomeUser");
    }

    public string WelcomeUser()
    {
        var user = (User)TempData[_userKey];
        return "Welcome " + user.Name;
    }
}

Expected (per behavior in Mvc 5)
Ouputs Hello {userName}

Actual
Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'User'.

@pranavkm pranavkm added the bug label Mar 26, 2015
@pranavkm
Copy link
Contributor Author

It looks like we Json serialize values in TempDataDictionary as opposed to using binary serialization in Mvc 5. Consequently complex types don't deserialize correctly. Perhaps we should consider disallowing storing non-primitive value types + strings in our default implementation if the (totally reasonable) intention is to avoid binary serialization.

@pranavkm
Copy link
Contributor Author

Minor note: In-memory session state is simply holding on to the object in memory, not serializing them. Consequently, you can store objects that cannot be deserialized in it

public class User
{
   public User(int id) {}
   public string Name { get; set; }
}

This is to counter @danroth27's suggestion to use Json.Net's type name handling behavior to serialize types.

@danroth27 danroth27 added this to the 6.0.0-beta5 milestone Mar 27, 2015
@danroth27
Copy link
Member

@pranavkm Consider restricting to only primitives, dictionaries of primitives and arrays of primitives for now.

@pranavkm pranavkm assigned ajaybhargavb and unassigned pranavkm Mar 30, 2015
@pranavkm
Copy link
Contributor Author

I think this was meant to be assigned to @ajaybhargavb. Let's talk about this before you start working on it.

@Fido789
Copy link

Fido789 commented Jul 9, 2015

In some early beta it was working as expected

var messages = TempData[PageMessagesKey] as IList<PageMessageModel>;

then in beta4 I had to deserialize objects from TempData like this

var messages = (TempData[PageMessagesKey] as Newtonsoft.Json.Linq.JArray)?.ToObject<List<PageMessageModel>>();

but it was working. And in beta5 it is not working at all. I don't think it's going to the right direction. How can I use TempData to store objects in beta5?

@pranavkm
Copy link
Contributor Author

pranavkm commented Jul 9, 2015

cc @Eilon. Could you respond to @Fido789 on what the suggested approach is if a user wants to stash complex data types?

@Eilon
Copy link
Member

Eilon commented Jul 10, 2015

@Fido789 can you log a new bug with the exact case that isn't working? We can have @ajaybhargavb take a look at that - he's the guy who wrote the codes.

@ajaybhargavb
Copy link
Contributor

@Eilon, I believe we made a design decision to not support serialization of complex data types by default. We currently throw an exception saying it can't be serialized.

@Eilon
Copy link
Member

Eilon commented Jul 10, 2015

Oh, right. We might still want to document some guidance on this then.

@Muchiachio
Copy link
Contributor

So how would you save complex data types, at least until the request is ended?
Is there any other way to do that without using TempData?

@Eilon
Copy link
Member

Eilon commented Jul 22, 2015

@Muchiachio I believe you can store the data in a dictionary as key/value pairs, and then re-assemble the object on the way out.

@Muchiachio
Copy link
Contributor

No @Eilon, as I understand this was made deliberately

[HttpGet]
public ActionResult Index()
{
    object value = new { Type = "Success", Message = "You got successfully redirected" };
    TempData["messages"] = value;

    return RedirectToAction("New");
}

throws and exception

System.InvalidOperationException
The 'Microsoft.AspNet.Mvc.SessionStateTempDataProvider' cannot serialize
an object of type 'System.Object' to session state.

I would be fine with that, if there is a way to pass these type of objects around without using TempData?

@Eilon
Copy link
Member

Eilon commented Jul 22, 2015

I mean a real Dictionary<string, string> etc.

@danroth27
Copy link
Member

Or you can do whatever serialization you want and store the data as a string or bytes.

@she2
Copy link

she2 commented Jul 25, 2016

I want to believe it is the worse kind of design. How do we store complex data then? Any alternative?

@Eilon
Copy link
Member

Eilon commented Jul 25, 2016

@she2 the recommendation is to serialize it yourself using a serializer that you know has the correct fidelity. The problem with doing this automatically is that there is no serializer that can serialize completely arbitrary data with full fidelity. And only the person writing the app knows what serializer matches the data structure that needs to be serialized. Once you have a string, you can stash that in the state.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants