如何为SQLServer会话模式序列化ViewData(ModelState)?

时间:2017-02-07 15:22:00

标签: c# asp.net sql-server

在我的MVC应用程序中,当发布的模型无效时,我希望模型状态保存到TempData,以便在重定向到另一个操作时显示。

这是我做的:

if (!ModelState.IsValid)
{
    TempData["ViewData"] = ViewData;
    return RedirectToAction("Edit", new { id = model.Id });
}

重定向到:

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

它在localhost中工作正常,但在服务器上失败了。

错误消息告诉:

  

无法序列化会话状态。在' StateServer'和' SQLServer'在模式下,ASP.NET将序列化会话状态对象,因此不允许使用不可序列化的对象或MarshalByRef对象。如果自定义会话状态存储在'自定义'中进行类似的序列化,则适用相同的限制。模式。

由于我们的服务器使用SQL Server会话模式,通常,当我们想要将某些模型保存到Session中时,我们在模型的开头添加[Serializable]。但是我们可以对ViewData做些什么呢?如何将 ViewDataDictionary 保存到我们的会话中?

2 个答案:

答案 0 :(得分:0)

您无法将ViewData或ViewDataDictionary存储在SQL Server会话状态中,因为它们不可序列化,也不确定您放入其中的数据是否可序列化。

如果本地应用程序配置为使用SQL Server作为会话状态存储,您应该能够看到相同的错误。

不是直接在会话状态中存储ViewData,而是应该从viewdata中获取实际对象,然后将该对象存储到会话状态。如果该对象的类型不可序列化,问题仍然会持续存在。

如果要存储modelstate,可以创建类来存储它。

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

您可以使用此数据结构存储模型状态信息并将其存储在会话中。并在需要时从会话中检索它并检索它并创建新的模型状态。

因此,简而言之,您无法在Sql Server会话状态中存储任何内容。您需要确保存储的值符合条件。

答案 1 :(得分:0)

这是一个详细的解决方案,灵感来自Chetan Ranpariya的答案。

可存储在会话中的可序列化模型。

SELECT sle.source_id, 
count(sle.*),
sum(coalesce(log_field20::numeric, 0)) || ' min' as duration_total
FROM custom_field_log_entries sle 
INNER JOIN student_enrollment se 
ON (sle.source_id=se.student_id and se.custom_9 is null 
AND se.syear = {SYEAR} 
AND se.end_date is null)
INNER JOIN schools sc on (se.school_id=sc.id) 
WHERE sle.field_id = 328
**AND log_field2::date BETWEEN '{START_DATE}' AND '{END_DATE}'**
AND (log_field20 ~ '^[0-9]+$' or log_field20 is null) --{SCHOOL_SPECIFIC} 
AND se.school_id = {SCHOOL_ID}
GROUP BY sle.source_id

一些扩展方法。

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

将模型状态设置为会话变量:

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

重定向后,在目标操作上,检查会话变量并转移到if (!ModelState.IsValid) { Session["ModelStateSummary"] = ModelState.ToSummary(); return RedirectToAction("Edit"); }

ViewData.ModelState

通过这种方式,我们将if (Session["ModelStateSummary"] != null) { var stateSummaries = (List<ModelStateSummary>)Session["ModelStateSummary"]; ModelState.Merge(stateSummaries.ToModelState()); } 从一个操作转移到另一个操作。