简体   繁体   English

在本地存储缓存数据

[英]Store the cache data locally

I develops a C# Winform application, it is a client and connect to web service to get data. 我开发了一个C#Winform应用程序,它是一个客户端并连接到Web服务以获取数据。 The data returned by webservice is a DataTable. webservice返回的数据是DataTable。 Client will display it on a DataGridView. 客户端将在DataGridView上显示它。

My problem is that: Client will take more time to get all data from server (web service is not local with client). 我的问题是:客户端将花费更多时间从服务器获取所有数据(Web服务不是客户端的本地服务)。 So I must to use a thread to get data. 所以我必须使用一个线程来获取数据。 This is my model: 这是我的模特:

Client create a thread to get data -> thread complete and send event to client -> client display data on datagridview on a form. 客户端创建一个线程来获取数据 - >线程完成并将事件发送到客户端 - >客户端在表单上的datagridview上显示数据。

However, when user closes the form, user can open this form in another time, and client must get data again. 但是,当用户关闭表单时,用户可以在另一个时间打开此表单,客户端必须再次获取数据。 This solution will cause the client slowly. 此解决方案将导致客户端缓慢。

So, I think about a cached data: 所以,我想一下缓存的数据:

Client <---get/add/edit/delete---> Cached Data ---get/add/edit/delete--->Server (web service) 客户端<--- get / add / edit / delete --->缓存数据---获取/添加/编辑/删除--->服务器(Web服务)

Please give me some suggestions. 请给我一些建议。 Example: cached data should be developed in another application which is same host with client? 示例:缓存数据应该在与客户端相同的主机的另一个应用程序中开发? Or cached data is running in client. 或者缓存数据在客户端中运行。 Please give me some techniques to implement this solution. 请给我一些实现此解决方案的技巧。

If having any examples, please give me. 如果有任何例子,请给我。

Thanks. 谢谢。

UPDATE : Hello everyone, maybe you think my problem so far. 更新:大家好,也许你认为我的问题到目前为止。 I only want to cache data in client's lifetime. 我只想在客户端的生命周期中缓存数据。 I think cache data should be stored in memory. 我认为缓存数据应该存储在内存中。 And when client want to get data, it will check from cache. 当客户端想要获取数据时,它将从缓存中进行检查。

If you're using C# 2.0 and you're prepared to ship System.Web as a dependency, then you can use the ASP.NET cache: 如果您正在使用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;
}

If you're not prepared to ship System.Web, then you might want to take a look at the Enterprise Library Caching block . 如果您不准备发运System.Web,那么您可能需要查看Enterprise Library Caching块

If you're on .NET 4.0, however, caching has been pushed into the System.Runtime.Caching namespace. 但是,如果您使用的是.NET 4.0,则缓存已被推送到System.Runtime.Caching命名空间。 To use this, you'll need to add a reference to System.Runtime.Caching, and then your code will look something like this: 要使用它,您需要添加对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;
}

All these caches run in-process to the client. 所有这些缓存都在进程中运行到客户端。 Because you're data is coming from a web service, as Adam says, you're going to have difficulty determining the freshness of the data - you'll have to make a judgement call on how often the data changes and how long you cache the data for. 因为你的数据来自网络服务,正如亚当所说,你将很难确定数据的新鲜度 - 你必须判断数据变化的频率和缓存时间的数据。

Do you have the ability to make changes/add to the webservice? 您是否有能力对Web服务进行更改/添加?

If you can Sync Services may be an option for you. 如果您可以同步服务可能是一个选项。 You can define which tables are syncronised, and all the sync stuff is managed for you. 您可以定义哪些表是同步的,并且为您管理所有同步内容。

Check out 查看

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

and shout if you need more information. 如果您需要更多信息,请大声喊叫。

Identify which objects you would like to serialize, and cache to isolated storage. 确定要序列化的对象,并缓存到隔离存储。 Specify the level of data isolation you would like (application level, user level, etc). 指定您希望的数据隔离级别(应用程序级别,用户级别等)。

Example: 例:

You could create a generic serializer, a very basic sample would look like this: 您可以创建一个通用的序列化程序,一个非常基本的示例将如下所示:

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

Note that you probably should put in some overloads to the Serialize and Deserialize methods to accomodate readers, or any other types you are actually using in your app (eg, XmlDocuments, etc). 请注意,您可能应该对Serialize和Deserialize方法进行一些重载,以容纳读者或您在应用程序中实际使用的任何其他类型(例如,XmlDocuments等)。

The operation to save to IsolatedStorage can be handled by a utility class (example below): 保存到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();
    }
}

Finally, remember to add the following using clauses: 最后,请记住添加以下using子句:

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

The actual code to use the classes above could look like this: 使用上面的类的实际代码可能如下所示:

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

This will save the instance you specify to be saved to the isolated storage. 这将保存您指定的实例以保存到隔离存储中。 To retrieve the instance, simply call: 要检索实例,只需调用:

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

Note: the sample I've provided only supports one serialized instance per type. 注意:我提供的示例仅支持每种类型一个序列化实例。 I'm not sure if you need more than that. 我不确定你是否需要更多。 Make whatever modifications you need to support further functionalities. 进行所需的任何修改以支持更多功能。

HTH! HTH!

You might try the Enterprise Library 's Caching Application Block . 您可以尝试企业库缓存应用程序块 It's easy to use, stores in memory and, if you ever need to later, it supports adding a backup location for persisting beyond the life of the application (such as to a database, isolated storage, file, etc.) and even encryption too. 它易于使用,存储在内存中,如果您以后需要,它还支持添加备份位置,以便在应用程序的生命周期内(例如数据库,隔离存储,文件等)持续存在,甚至加密。

Use EntLib 3.1 if you're stuck with .NET 2.0. 如果你坚持使用.NET 2.0,请使用EntLib 3.1。 There's not much new (for caching, at least) in the newer EntLibs aside from better customization support. 除了更好的自定义支持之外,新的EntLibs中没有太多新的(至少用于缓存)。

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

Your only concern then is deciding when the cache has gone stale. 您唯一关心的是决定缓存何时过时。 Perhaps timestamp the file? 也许是时间戳文件?

In our implementation every row in the database has a last-updated timestamp. 在我们的实现中,数据库中的每一行都有一个最后更新的时间戳。 Every time our client application accesses a table we select the latest last-updated timestamp from the cache and send that value to the server. 每次我们的客户端应用程序访问表时,我们从缓存中选择最新的最后更新时间戳,并将该值发送到服务器。 The server responds with all the rows that have newer timestamps. 服务器响应所有具有较新时间戳的行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM