ASP.NET - 在不序列化的情况下保存在视图状态中

ASP.NET - Saving in Viewstate Without serializing

我试图在 Viewstate 中存储一个复杂的对象,以避免每次在页面加载时调用它。我知道它需要序列化才能保存并从 Viewstate 中检索,这意味着我的 class 应该标记为 [Serializable]

这是一个相当复杂的实体,基本上我希望避免将每个 class 标记为可序列化,因为它可能会影响我用于映射的其他依赖项。

Class Article
{
    Albums albumList { get; set; }
    Authors authorList { get; set; }
    ...
}

是否有可能在不序列化的情况下保存和检索视图状态对象?

您可以改用 ASP.NET Session 对象(这避免了序列化路径,因为 Session 中的所有内容都存储为 Object),如下所示:

var theArticle = new Article();

Session["MyArticle"] = theArticle;

Session 中的所有内容都存储为对象,因此当您检索 Article 对象时,您需要将其转换为 Article,如下所示:

var myArticleFromSession = Session["MyArticle"] as Article;

注意:建议在尝试访问该值之前检查 Session 键是否确实存在,如下所示:

if(Session["MyArticle"] != null)
{
    // The key MyArticle exists, so it is safe to attempt to get the object value
    var myArticleFromSession = Session["MyArticle"] as Article;

    // Since we used as to attempt the cast, 
    // then myArticleFromSession will be null if the cast failed 
    // so check for null before using myArticleFromSession
    if(myArticleFromSession != null)
    {
        // Use myArticleFromSession here

    }
}

如果可能,应避免序列化,因为它相对较慢(扩展性不好)。

如果您希望在回发之间或跨页面缓存特定对象,请使用 ASP.NET Session 对象进行特定于会话的缓存,Application 对象用于站点范围缓存,或将 System.Web.Caching.Cache 用于您自己的自定义缓存行为。您还可以缓存 ASP.NET 个页面或部分页面的输出。更多信息在这里:ASP.NET Caching

但是如果您希望缓存整个页面的视图状态,可以选择服务器端视图状态持久化。在这种情况下,您需要创建一个新的 BasePage。例如,当浏览器限制非常大的视图状态的大小时,这非常有用。您可以在此处获得有关此方法的更多信息:Server Side Viewstate

在我看来,从您的用例来看,"to avoid calling it everytime on page load" 急需缓存。我想如果你想让它过期,可以设置一些依赖关系,它 might work better than session(我们不知道所有的细节)。

现在,您可能可以使用 json.net,它可以帮助您在不更改对象的情况下序列化您的信息。只是不要滥用视图状态,如果让它增长,它会很快变得令人讨厌。使用会话或缓存(如果它满足您的需要)是可以在长期 运行 中更好地扩展的东西。

如果这是显示内容,还请查看 Output cache,因为也许您可以在用户控件或其他内容中分隔重复的内容。

综上所述,我想添加一个你实际使用 JSON.net 询问的小例子(从他们那里偷来的例子):

//Doesnt need to be marked as serializable
Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string[] { "Small" };
//Use this string to save into view state
string json = JsonConvert.SerializeObject(product);
ViewState["something"]=json;

之后,从 ViewState[something] 取回字符串并反序列化。

string json = (string)ViewState["something"];
Product m = JsonConvert.DeserializeObject<Product>(json);

警告,未经编译而编写的代码。

另一种可能的解决方案是您可以将所有非必需属性映射为 [NonSerialized],以便只使用一次必需属性。我遇到了类似的问题并选择了这个选项。

所以假设在上面的例子中你想要专辑而不是艺术家那么你的class将变成如下

[Serializable]
Class Article
{
    Albums albumList { get; set; }

    [NonSerialized]
    Authors authorList { get; set; }
    ...
}