【问题标题】:How to store only a part of an object in ASP.Net session?如何在 ASP.Net 会话中仅存储对象的一部分?
【发布时间】:2013-12-09 12:38:58
【问题描述】:

我处理了一些可以引用大型 DataTable 的对象。我想在没有 DataTable 的情况下将这些对象存储在会话中,因为它们可以很容易地重新生成,并且我想节省一些内存。

有没有一种有效的方法来做到这一点?

我尝试过的瘦身:

  • 考虑一下
  • 避免在想到第一个解决方法时感觉很好,因为可能存在更好的方法
  • 承认我的知识有限
  • 在 stackoverflow 上提问
  • 希望有一个有趣的发现

【问题讨论】:

  • 您可以为该对象的数据表特定属性或变量分配空值。
  • 何时执行此操作以确保当前进程不再使用数据表?
  • 或者创建一个新类,其中包含您关心的所有这些值的属性,并拥有一个接受现有对象类型的构造函数,并将该新类实例存储在会话中?
  • 您想为所有数据表自动执行此操作吗?您想明确地针对特定情况执行此操作吗?是否要使用自定义属性来装饰不应该序列化的属性?你有什么尝试,什么失败了?
  • 如果某个属性能发挥作用,请告诉我。

标签: c# asp.net session memory


【解决方案1】:

您可以使用通用解决方案来取消使用自定义属性修饰的类的属性。例如,您可以创建此属性和类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace MvcApp
{
    [AttributeUsage(AttributeTargets.Property)]
    public class NullifyAttribute : Attribute
    {
    }

    public class PropertyNullifier
    {
        public static T Nullify<T>(T original)
            where T : class
        {
            // Limitations:
            // 1) only works for POCOs with public properties: t.GetProperties()
            // 2) only works for classes with public constructor
            // 3) it's not recursive
            Type t = original.GetType();
            // This looks for all the properties that are not marked with nullified
            List<PropertyInfo> notNullifiedProperties = 
                t.GetProperties() // 1)
                .Where(p => !p.GetCustomAttributes(typeof (NullifyAttribute), true).Any())
                .ToList();
            // This creates an instance of the object
            T copy = Activator.CreateInstance<T>(); // 2)
            // And this copy the non-nullified properties
            foreach (var p in notNullifiedProperties)
            {
                p.SetValue(copy, p.GetValue(original)); // 3) apply recursion to 2nd parameter
            }
            return copy;
        }
    }
}

注意 cmets 的限制!!至少,这不会修改原始对象,而是进行浅拷贝(将引用复制到引用属性),速度非常快。额外的限制是速度。这可以通过多种方式进行改进,例如缓存未无效的属性,使用反射而不是激活器,将其修改为仅在存在可无效属性时创建副本。最后一个改进很容易实现。添加此代码:if (notNullifiedProperties.Count == 0) return original;

然后,在将对象存储到 Session 之前,将其属性无效并存储此对象的无效副本。此单元测试解释了如何使无效(您将无效对象存储在会话中)。

using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcApp;

namespace Test.MvcApp
{
    public class SampleClass
    {
        [Nullify]
        public string Name { get; set; }
        public int Age { get; set; }
    }

    [TestClass]
    public class PropertyNullifierTest
    {
        [TestMethod]
        public void TestMethod1()
        {
            SampleClass sampleObject = new SampleClass
            {
                Name = "John Smith",
                Age = 22,
            };

            SampleClass nullified = PropertyNullifier.Nullify(sampleObject);

            Assert.IsNull(nullified.Name);
            Assert.AreEqual(sampleObject.Age, nullified.Age);
        }
    }
}

但是,使用此解决方案,您仍然必须在存储到会话之前使用 nullifier。 另一种选择是创建自己的类来存储会话,并更改 web.config 以使用它。这样就可以在存储前自动作废。

这不是一个非常通用的解决方案。所以你可以做一些更复杂的事情:创建你自己的自定义会话状态存储,并配置 web.confgi 以使用它。这里有一个完整的工作示例:of this solution。您必须修改此示例以使用 nullifier 类或使用它修改序列化方法以忽略自定义属性修饰属性,检查它们是否被修饰(使用我的代码的对应部分)。

采取额外的工作使其或多或少自动化,并确定这是否有效,取决于您的项目细节。

想要更轻松吗?好吧,你很幸运。如果更改Session mode to State Server,它将自动使用序列化。然后您可以使用standard NonSerialized attribute。但这可能很危险:如果你尝试存储不可序列化的对象,你会得到一个异常。

正如您所见,没有最佳解决方案:只选择最适合您的解决方案。

【讨论】:

    【解决方案2】:

    您可以制作如下所示的接口并将其应用于您想要此行为的类

    public interface IClearBeforeSessionStore
    {
      public void ClearWhichAreBigger();
    } 
    
    public class A : IClearBeforeSessionStore
    {
      public DataTable dt {get;set;}
      public string AnyString { get;set;}
    
      public void ClearWhichAreBigger()
      {
         this.dt = null;
      }
    }
    

    像这样在会话中存储一个类对象

    A objA = new A();
    objA.AnyString = "Object A";
    objA.dt = new DataTable(); // or any existing one
    
    Session["objA"] = objA.ClearWhichAreBigger();
    

    当你像下面这样从会话中取回它时,你只能访问 AnyString 属性

    A objA = Session["objA"] as A;
    if(objA.AnyString == "Object A" && objA.dt == null)
    {
       // yes I am from session !!!!
    }
    

    【讨论】:

      【解决方案3】:

      您可以向类中添加一个“复制构造函数”,以复制除您不想要的成员之外的所有成员,如下所示:

      public class BigData
      {
        private string _someValue;
        private DataSet _bigDataSet;
      
        public BigData()
        {
            ...
        }
      
        public BigData(BigData toBeCloned)
        {
           this._someValue = toBeCloed._someValue;
           // Don't copy _bigDataSet here!
        }
      }
      

      然后您可以像这样添加到会话中:

      session["BigDataWithoutDataSet"] = new BigData(bigDataContainingDataSet);
      

      【讨论】:

        猜你喜欢
        • 2016-06-29
        • 1970-01-01
        • 2017-08-25
        • 1970-01-01
        • 2021-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多