简体   繁体   中英

Store the cache data locally

I develops a C# Winform application, it is a client and connect to web service to get data. The data returned by webservice is a DataTable. Client will display it on a DataGridView.

My problem is that: Client will take more time to get all data from server (web service is not local with client). 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.

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)

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:

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 .

If you're on .NET 4.0, however, caching has been pushed into the System.Runtime.Caching namespace. To use this, you'll need to add a reference to System.Runtime.Caching, and then your code will look something like this:

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?

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

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).

The operation to save to IsolatedStorage can be handled by a utility class (example below):

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 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!

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. There's not much new (for caching, at least) in the newer EntLibs aside from better customization support.

You can serialise the DataTable to 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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