将复杂对象存储在TempData中


72

我一直在尝试通过使用TempData的重定向将数据传递给操作,如下所示:

if (!ModelState.IsValid)
{
    TempData["ErrorMessages"] = ModelState;
    return RedirectToAction("Product", "ProductDetails", new { code = model.ProductCode });
}

但不幸的是,它失败并显示以下消息:

System.InvalidOperationExceptionMicrosoft.AspNet.Mvc.SessionStateTempDataProvider'不能序列类型的对象'ModelStateDictionary'到会话状态”。

在Github的MVC项目中发现了一个问题,但是尽管它解释了为什么我会收到此错误,但我看不到什么是可行的选择。

一种选择是将对象序列化为json字符串,然后反序列化它并重建ModelState。这是最好的方法吗?我是否需要考虑任何潜在的性能问题?

最后,对于序列化复杂对象或使用不涉及使用的其他模式,是否有其他选择TempData


您不应该这样做。如果modelstate无效,则默认行为是返回与无效模型相同的视图。因此,您只应返回View(model); 而不是重定向到行动
hjgraca

1
这只是一个例子,我正在寻找一种在TempData中存储任何复杂对象的方法,而不必在ModelState中存储。另外,在
某些

1
@hjgraca这种情况的用例是具有多个局部视图的视图,用于添加和编辑数据列表。例如,视图的模型实际上是模型的列表,然后有一个内联添加表单,该表单具有自己的模型(需要将其错误发送回去),然后每个项目也都进行内联编辑(每个都有自己的错误) )。使用客户端框架(例如Angular)可以轻松完成此操作,但使用Razor则不那么容易。
Mike Perrenoud

仅供参考,您不能仅序列化为JSON,因为ModelError类没有适当的构造函数。实际上,这就是一个有问题的孩子,内部的ModelError类。因此,我认为解决方案是序列化KVP,然后反序列化该KVP并将其添加回去。完成过滤后,我将发布这些过滤器。
Mike Perrenoud

@MichaelPerrenoud我正在按照以下步骤在TempData中存储自定义类(而非ModelState)。我只是想知道是否有更好的方法。
elolos

Answers:


134

您可以创建如下扩展方法:

public static class TempDataExtensions
{
    public static void Put<T>(this ITempDataDictionary tempData, string key, T value) where T : class
    {
        tempData[key] = JsonConvert.SerializeObject(value);
    }

    public static T Get<T>(this ITempDataDictionary tempData, string key) where T : class
    {
        object o;
        tempData.TryGetValue(key, out o);
        return o == null ? null : JsonConvert.DeserializeObject<T>((string)o);
    }
}

并且,您可以按以下方式使用它们:

说的objectA是类型ClassA。您可以使用上述扩展方法将其添加到临时数据字典中,如下所示:

TempData.Put("key", objectA);

要检索它,您可以执行以下操作:

var value = TempData.Get<ClassA>("key") 其中value检索将型ClassA


奇迹般有效。爱牛顿!
斯蒂芬·麦克道威尔'18

1
我还通过标记将固定此Serializable,我用的对象的类属性被放入TempData
brendonparker

@brendonparker这对我不起作用,可能仅取决于对象。上面的代码似乎无处不在,而IMO势必会导致控制器和视图设置混乱。
perustaja '20年

@brendonparker我已经使用[Serializable()]属性并实现了ISerializable,但是它没有用。您可以分享您的解决方案吗?
Abubakar Riaz

15

我无法发表评论,但我也添加了PEEK,非常适合检查是否存在或已阅读,并且不能删除下一个GET。

public static T Peek<T>(this ITempDataDictionary tempData, string key) where T : class
{
    object o = tempData.Peek(key);
    return o == null ? null : JsonConvert.DeserializeObject<T>((string)o);
}

var value = TempData.Peek<ClassA>("key") where value retrieved will be of type ClassA

5

在.Net core 3.1及更高版本中使用System.Text.Json

using System.Text.Json;

    public static class TempDataHelper
    {
        public static void Put<T>(this ITempDataDictionary tempData, string key, T value) where T : class
        {
            tempData[key] = JsonSerializer.Serialize(value);
        }

        public static T Get<T>(this ITempDataDictionary tempData, string key) where T : class
        {
            tempData.TryGetValue(key, out object o);
            return o == null ? null : JsonSerializer.Deserialize<T>((string)o);
        }

        public static T Peek<T>(this ITempDataDictionary tempData, string key) where T : class
        {
            object o = tempData.Peek(key);
            return o == null ? null : JsonSerializer.Deserialize<T>((string)o);
        }
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.