在本地存储缓存数据

时间:2010-06-15 10:31:54

标签: c# winforms caching

我开发了一个C#Winform应用程序,它是一个客户端并连接到Web服务以获取数据。 webservice返回的数据是DataTable。客户端将在DataGridView上显示它。

我的问题是:客户端将花费更多时间从服务器获取所有数据(Web服务不是客户端的本地服务)。所以我必须使用一个线程来获取数据。这是我的模特:

客户创建一个线程来获取数据 - >线程完成并将事件发送给客户端 - >客户端在表单上的datagridview上显示数据。

但是,当用户关闭表单时,用户可以在其他时间打开此表单,客户端必须再次获取数据。此解决方案将导致客户端缓慢。

所以,我想一下缓存的数据:

客户< ---获取/添加/编辑/删除--->缓存数据---获取/添加/编辑/删除--->服务器(Web服务)

请给我一些建议。 示例:缓存数据应该在与客户端相同的主机的另一个应用程序中开发?或者缓存数据在客户端中运行。 请给我一些实现此解决方案的技巧。

如果有任何例子,请给我。

感谢。

更新:大家好,也许你认为我的问题到目前为止。我只想在客户端的生命周期中缓存数据。我认为缓存数据应该存储在内存中。当客户想要获取数据时,它将从缓存中进行检查。

6 个答案:

答案 0 :(得分:4)

如果您正在使用C#2.0 ,那么您已准备好将System.Web作为依赖项发布,那么您可以使用ASP.NET缓存:

using System.Web;
using System.Web.Caching;

Cache webCache;

webCache = HttpContext.Current.Cache;

// See if there's a cached item already
cachedObject = webCache.Get("MyCacheItem");

if (cachedObject == null)
{
    // If there's nothing in the cache, call the web service to get a new item
    webServiceResult = new Object();

    // Cache the web service result for five minutes
    webCache.Add("MyCacheItem", webServiceResult, null, DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);
}
else
{
    // Item already in the cache - cast it to the right type
    webServiceResult = (object)cachedObject;
}

如果您不准备发运System.Web,那么您可能需要查看Enterprise Library Caching block

但是,如果您使用的是.NET 4.0,则缓存已被推送到System.Runtime.Caching命名空间。要使用它,您需要添加对System.Runtime.Caching的引用,然后您的代码将如下所示:

using System.Runtime.Caching;

MemoryCache cache;
object cachedObject;
object webServiceResult;

cache = new MemoryCache("StackOverflow");

cachedObject = cache.Get("MyCacheItem");

if (cachedObject == null)
{
    // Call the web service
    webServiceResult = new Object();

    cache.Add("MyCacheItem", webServiceResult, DateTime.Now.AddMinutes(5));
}
else
{
    webServiceResult = (object)cachedObject;
}

所有这些缓存都在进程中运行到客户端。因为你的数据来自网络服务,正如亚当所说,你将很难确定数据的新鲜度 - 你必须判断数据变化的频率和缓存时间。的数据。

答案 1 :(得分:2)

您是否有能力对网络服务进行更改/添加?

如果您可以为您提供同步服务。您可以定义哪些表是同步的,并且所有同步内容都是为您管理的。

结帐

http://msdn.microsoft.com/en-us/sync/default.aspx

如果您需要更多信息,请大声喊叫。

答案 2 :(得分:1)

确定要序列化的对象,并缓存到隔离存储。指定您希望的数据隔离级别(应用程序级别,用户级别等)。

示例:

您可以创建一个通用序列化程序,一个非常基本的示例如下所示:

public class SampleDataSerializer
{
    public static void Deserialize<T>(out T data, Stream stm)
    {
        var xs = new XmlSerializer(typeof(T));
        data = (T)xs.Deserialize(stm);
    }

    public static void Serialize<T>(T data, Stream stm)
    {
        try
        {
            var xs = new XmlSerializer(typeof(T));
            xs.Serialize(stm, data);
        }
        catch (Exception e)
        {
            throw;
        }
    }
}

请注意,您可能应该对Serialize和Deserialize方法进行一些重载,以容纳读者或您在应用中实际使用的任何其他类型(例如,XmlDocuments等)。

保存到IsolatedStorage的操作可以由实用程序类处理(下面的示例):

public class SampleIsolatedStorageManager : IDisposable
{
    private string filename;
    private string directoryname;
    IsolatedStorageFile isf;

    public SampleIsolatedStorageManager()
    {
        filename = string.Empty;
        directoryname = string.Empty;

        // create an ISF scoped to domain user...
        isf = IsolatedStorageFile.GetStore(IsolatedStorageScope.User |
            IsolatedStorageScope.Assembly | IsolatedStorageScope.Domain,
            typeof(System.Security.Policy.Url), typeof(System.Security.Policy.Url));
    }

    public void Save<T>(T parm)
    {
        using (IsolatedStorageFileStream stm = GetStreamByStoredType<T>(FileMode.Create))
        {
            SampleDataSerializer.Serialize<T>(parm, stm);
        }
    }

    public T Restore<T>() where T : new()
    {
        try
        {
            if (GetFileNameByType<T>().Length > 0)
            {
                T result = new T();

                using (IsolatedStorageFileStream stm = GetStreamByStoredType<T>(FileMode.Open))
                {
                    SampleDataSerializer.Deserialize<T>(out result, stm);
                }

                return result;
            }
            else
            {
                return default(T);
            }
        }
        catch
        {
            try
            {
                Clear<T>();
            }
            catch
            {
            }

            return default(T);
        }
    }

    public void Clear<T>()
    {
        if (isf.GetFileNames(GetFileNameByType<T>()).Length > 0)
        {
            isf.DeleteFile(GetFileNameByType<T>());
        }
    }

    private string GetFileNameByType<T>()
    {
        return typeof(T).Name + ".cache";
    }

    private IsolatedStorageFileStream GetStreamByStoredType<T>(FileMode mode)
    {
        var stm = new IsolatedStorageFileStream(GetFileNameByType<T>(), mode, isf);
        return stm;
    }

    #region IDisposable Members

    public void Dispose()
    {
        isf.Close();
    }
}

最后,请记住添加以下using子句:

using System.IO;
using System.IO.IsolatedStorage;
using System.Xml.Serialization;

使用上述类的实际代码可能如下所示:

var myClass = new MyClass();
myClass.name = "something";
using (var mgr = new SampleIsolatedStorageManager())
{
    mgr.Save<MyClass>(myClass);
}

这将保存您指定要保存到隔离存储的实例。要检索实例,只需调用:

using (var mgr = new SampleIsolatedStorageManager())
{
    mgr.Restore<MyClass>();
}

注意:我提供的示例仅支持每种类型一个序列化实例。我不确定你是否需要更多。进行任何修改以支持更多功能。

HTH!

答案 3 :(得分:1)

您可以尝试Enterprise LibraryCaching Application Block。它易于使用,存储在内存中,如果您以后需要,它还支持添加备份位置,以便在应用程序的生命周期内(例如数据库,隔离存储,文件等)持续存在,甚至加密

如果您遇到.NET 2.0,请使用EntLib 3.1。除了更好的自定义支持之外,新的EntLibs中没有太多新的(至少用于缓存)。

答案 4 :(得分:0)

您可以将DataTable序列化为file: http://forums.asp.net/t/1441971.aspx

您唯一关心的是决定缓存何时失效。也许是时间戳文件?

答案 5 :(得分:0)

在我们的实现中,数据库中的每一行都有一个最后更新的时间戳。每次我们的客户端应用程序访问表时,我们从缓存中选择最新的最后更新时间戳,并将该值发送到服务器。服务器响应所有具有较新时间戳的行。