6

我有一个巨大的 XML 文档,我必须对其进行解析以生成域对象。

因为文档很大,我不想每次用户请求它时都解析它,但只是第一次,然后将所有对象保存到缓存中。

public List<Product> GetXMLProducts()
{
    if (HttpRuntime.Cache.Get("ProductsXML") != null)
    {
        return (List<Product>)(HttpRuntime.Cache.Get("ProductsXML"));
    }

    string xmlPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content\\Products.xml");
    XmlReader reader = XmlReader.Create(xmlPath);
    XDocument doc = XDocument.Load(reader);

    List<Product> productsList = new List<Product>();
    // Parsing the products element

    HttpRuntime.Cache.Insert("ProductsXML", productsList);
    return productsList;
}

我怎样才能使这个函数在单例中工作并且是线程安全的?

修复了将对象保存到缓存中的方法(是复制粘贴错误)

4

2 回答 2

12

创建一个惰性静态并在应用程序的生命周期内保存在内存中。并且不要忘记“真实”部分,这就是使其线程安全的原因。

public static readonly Lazy<List<Product>> _product = new Lazy<List<Products>>(() => GetProducts(), true);

要将其添加到您的模型中,只需将其设为私有并返回 _product.Value;

public MyModel
{
    ... bunch of methods/properties

    private static readonly Lazy<List<Product>> _products = new Lazy<List<Products>>(() => GetProducts(), true);

    private static List<Product> GetProducts()
    {
        return DsLayer.GetProducts();

    }

    public List<Product> Products { get { return _products.Value; } }
}

要使用 Lazy<> 创建单例,请使用此模式。

public MyClass
{
    private static readonly Lazy<MyClass> _myClass = new Lazy<MyClass>(() => new MyClass(), true);

    private MyClass(){}

    public static MyClass Instance { get { return _myClass.Value; } }
}

更新/编辑:

在上下文中使用的另一种惰性模式(即会话)

保存在会话中的一些模型:

public MyModel
{
   private List<Product> _currentProducts = null;
   public List<Product> CurrentProducts 
   {
      get
      {
         return this._currentProducts ?? (_currentProducts = ProductDataLayer.GetProducts(this.CurrentCustomer));
      }
   }
}
于 2012-07-16T10:40:49.420 回答
2

记录在案 - 懒惰的静态(Chris Gessler 的回答,我给了 +1)是一个很好的解决方案;在这种情况下,因为您总是希望内存中的数据。该答案专门针对Cache(解决您有些混乱的代码)的使用并带来了另一种初始化网站的方法。

执行此操作的传统方法是Application_Start在 Global.asax(.cs) 中的处理程序中。但是,我将展示另一种不错的方式:

使用 Nuget 将WebActivator包添加到您的网站。

然后将以下代码添加到您在项目中创建的新文件夹中的新 .cs 文件中,名为App_Start

[assembly: WebActivator.PreApplicationStartMethod(typeof(*your_namespace*.MyInit), 
  "Start", Order = 0)]
namespace *your_namespace*
{

  public static class MyInit {
    public static void Start() {
      string xmlPath = HostingEnvironment.MapPath("~/Content/Products.xml");
      using(var reader = XmlReader.Create(xmlPath)) {
       XDocument doc = XDocument.Load(reader);  

       List<Product> productsList = new List<Product>();  
       // Parsing the products element

       HttpRuntime.Cache.Insert("ProductsXML", productsList); 
      }
    }
  }
}

注意 - Cache.Insert 的正确使用,以及using用于流阅读器的 a。您的原始代码还有其他奇怪的逻辑和语义错误 - 例如尝试分配函数的结果并在缓存中返回值为空的值。

另请注意,您需要在上面的代码中引入一些命名空间 - 并注意*your_namespace*.

于 2012-07-16T10:49:52.287 回答