【问题标题】:Store complex object in TempData在 TempData 中存储复杂对象
【发布时间】:2016-01-06 17:14:05
【问题描述】:

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

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

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

'System.InvalidOperationException Microsoft.AspNet.Mvc.SessionStateTempDataProvider' 无法序列化 'ModelStateDictionary' 类型的对象到会话状态。'

我在 the MVC project in Github 中发现了一个问题,虽然它解释了我收到此错误的原因,但我看不出有什么可行的替代方案。

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

最后,对于序列化复杂对象或使用不涉及使用TempData 的其他模式,是否有任何替代方案?

【问题讨论】:

  • 你不应该这样做。如果模型状态无效,则默认行为只是返回与无效模型相同的视图。所以你应该只这样做 return View(model);而不是重定向到行动
  • 这只是一个例子,我正在寻找一种将任何复杂对象存储在 TempData 中的方法,不一定是 ModelState。此外,在某些情况下您可能无法遵循您的建议,我同意这是最佳做法
  • @hjgraca 这种情况的用例是一个视图,它具有多个用于添加和编辑数据列表的部分视图。例如,视图的模型实际上是模型的列表,然后有一个内联添加表单,它有自己的模型(其错误需要发回),然后每个项目也被内联编辑(每个项目都有自己的错误)。使用 Angular 等客户端框架很容易做到这一点,但使用 Razor 就不太容易了。
  • 仅供参考,您不能只序列化为 JSON,因为 ModelError 类没有适当的构造函数。事实上,这是一个有问题的孩子,内部 ModelError 类。因此,我认为解决方案是序列化 KVP,然后反序列化并将它们添加回来。完成后我会发布这些过滤器。
  • @MichaelPerrenoud 我正在按照这些思路在 TempData 中存储自定义类(不是 ModelState)。我只是想知道是否有更好的方法。

标签: c# asp.net-core asp.net-core-mvc tempdata


【解决方案1】:

您可以像这样创建扩展方法:

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

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

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

TempData.Put("key", objectA);

要检索它,您可以这样做:

var value = TempData.Get&lt;ClassA&gt;("key") 其中value 检索到的类型为ClassA

【讨论】:

  • 像魅力一样工作。爱 Newtonsoft!
  • 我还通过标记将Serializable 属性添加到我用于放置到TempData 中的对象的类来解决此问题
  • @brendonparker 这对我不起作用,可能只是取决于对象。上面的代码似乎到处都是复制粘贴的,IMO 势必会导致控制器和视图设置混乱。
  • @brendonparker 我使用了 [Serializable()] 属性并实现了 ISerializable,但它不起作用。你能分享你的解决方案吗?
  • @EduardoAlmeida 对于字符串、整数或布尔值,只需使用“TempData[key] = value;”直接。
【解决方案2】:

我无法发表评论,但我也添加了一个 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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 您是否在 *.csproj 中包含
    • 该死,我没有意识到这是一个包裹。我删除了我之前的评论。
    猜你喜欢
    • 2011-11-05
    • 1970-01-01
    • 2020-12-29
    • 2014-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多