我开发了一个C#Winform应用程序,它是一个客户端并连接到Web服务以获取数据。 webservice返回的数据是DataTable。客户端将在DataGridView上显示它。
我的问题是:客户端将花费更多时间从服务器获取所有数据(Web服务不是客户端的本地服务)。所以我必须使用一个线程来获取数据。这是我的模特:
客户创建一个线程来获取数据 - >线程完成并将事件发送给客户端 - >客户端在表单上的datagridview上显示数据。
但是,当用户关闭表单时,用户可以在其他时间打开此表单,客户端必须再次获取数据。此解决方案将导致客户端缓慢。
所以,我想一下缓存的数据:
客户< ---获取/添加/编辑/删除--->缓存数据---获取/添加/编辑/删除--->服务器(Web服务)
请给我一些建议。 示例:缓存数据应该在与客户端相同的主机的另一个应用程序中开发?或者缓存数据在客户端中运行。 请给我一些实现此解决方案的技巧。
如果有任何例子,请给我。
感谢。
更新:大家好,也许你认为我的问题到目前为止。我只想在客户端的生命周期中缓存数据。我认为缓存数据应该存储在内存中。当客户想要获取数据时,它将从缓存中进行检查。
答案 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 Library的Caching Application Block。它易于使用,存储在内存中,如果您以后需要,它还支持添加备份位置,以便在应用程序的生命周期内(例如数据库,隔离存储,文件等)持续存在,甚至加密
如果您遇到.NET 2.0,请使用EntLib 3.1。除了更好的自定义支持之外,新的EntLibs中没有太多新的(至少用于缓存)。
答案 4 :(得分:0)
您可以将DataTable序列化为file: http://forums.asp.net/t/1441971.aspx
您唯一关心的是决定缓存何时失效。也许是时间戳文件?
答案 5 :(得分:0)
在我们的实现中,数据库中的每一行都有一个最后更新的时间戳。每次我们的客户端应用程序访问表时,我们从缓存中选择最新的最后更新时间戳,并将该值发送到服务器。服务器响应所有具有较新时间戳的行。