当前位置: 动力学知识库 > 问答 > 编程问答 >

c# - How to serialize ViewData (ModelState) for SQLServer Session Mode?

问题描述:

In my MVC application, when a model posted is invalid, I want the model state saved into TempData so that it can show when redirecting to another action.

Here is what I did:

if (!ModelState.IsValid)

{

TempData["ViewData"] = ViewData;

return RedirectToAction("Edit", new { id = model.Id });

}

Redirect to:

public ActionResult Edit(Guid id)

{

var model = Services.Get(id);

if (TempData["ViewData"] != null)

{

ViewData = (ViewDataDictionary)TempData["ViewData"];

}

ViewBag.HasUpdated = TempData["HasUpdated"];

return View(model);

}

It works fine in localhost, but failed on the server.

The error message is telling:

Unable to serialize the session state. In 'StateServer' and 'SQLServer' mode, ASP.NET will serialize the session state objects, and as a result non-serializable objects or MarshalByRef objects are not permitted. The same restriction applies if similar serialization is done by the custom session state store in 'Custom' mode.

Since our server uses SQL Server Session Mode, usually, when we want to save some model into Session, we add [Serializable] at the beginning of the model. But what can we do with the ViewData? How to save ViewDataDictionary into our session?

网友答案:

You can not store the ViewData or ViewDataDictionary in SQL Server Session State as they are not serializable and also it is not sure that the data you put in them are serializable.

You should be able to see the same error if the local application is configured to use SQL server as Session State Store.

Instead of Storing the ViewData directly in the session state you should get the actual object out of the viewdata and then store that object to the session state. Again the problem will still persist if the type of that object is not serializable.

If you want to store modelstate you can create class to store it.

[Serializable]
public class ModelStateStore
{
     public List<ModelStateData> {get;set;}
}

[Serializable]
public class ModelStateData 
{
     public string PropertyName {get;set;}
     public bool IsValid {get;set;}
     public string ErrorMessage {get;set;}
}

You can store the model state information using this data structure and store it in the session. And retrieve it and create new modelstate by retrieving it from session whenever you need it.

So in short you can not store anything and everything in Sql Server Session State. You need to make sure that the value you are storing there follows the conditions.

网友答案:

Here is a detailed solution, inspired by Chetan Ranpariya's answer.

A serializable model to store in session.

[Serializable]
public class ModelStateSummary
{
    public string PropertyName { get; set; }
    public string[] ErrorMessages { get; set; }
}

Some extension methods.

public static class ModelStateExtensions
{
    public static IEnumerable<ModelStateSummary> ToSummary(this ModelStateDictionary modelState)
    {
        return modelState.Select(state => new ModelStateSummary
        {
            PropertyName = state.Key,
            ErrorMessages = state.Value.Errors.Select(x => x.ErrorMessage).ToArray()
        });
    }

    public static ModelStateDictionary ToModelState(this IEnumerable<ModelStateSummary> summary)
    {
        var modelStates = new ModelStateDictionary();
        foreach (var modelState in summary)
        {
            var data = new ModelState();
            foreach (var errorMessage in modelState.ErrorMessages)
            {
                data.Errors.Add(new ModelError(errorMessage));
            }
            modelStates.Add(modelState.PropertyName, data);
        }
        return modelStates;
    }
}

To set the model state to a session variable:

if (!ModelState.IsValid)
{
    Session["ModelStateSummary"] = ModelState.ToSummary();
    return RedirectToAction("Edit");
}

After the redirect, on the target action, check the session variable and transfer into the ViewData.ModelState.

if (Session["ModelStateSummary"] != null)
{
    var stateSummaries = (List<ModelStateSummary>)Session["ModelStateSummary"];
    ModelState.Merge(stateSummaries.ToModelState()); 
}

In this way, we transfer the ModelState from one action to another.

分享给朋友:
您可能感兴趣的文章:
随机阅读: