简体   繁体   中英

rich client data handling and caching patterns

I am developing a rich client application using WPF-PRISM-MVVM.
The client interacts with a repository service which provides CRUD functionality and publishes any changes for domain entities via WCF channel.
The client handles domain entities cache in order to improve performance and provide offline functionality.
For that purpose I wrote a repository agent service which lives on the client side and wraps the repository service and handles caching and changes propagation to the relevant client side component that have interests in domain entities changes.

After the long introduction my question is this the way to do it?
Are there any client side data handling and caching patterns that I should aware of?

Cheers,
Doron

We use AOP in the form of PostSharp for our client side caching, we simply add an attribute to a method and viola it is cached :

Our aspect looks like this- it defers the actual cache implementation to an instance of ICacheService but you get the idea.

[Serializable]
[MulticastAttributeUsage(MulticastTargets.Method, PersistMetaData = true)]
public class MethodCacheAttribute : MethodInterceptionAspect
{

    public const int DefaultCacheSeconds = 600;
    private ICacheService CacheService { get; set; }
    private string methodName;

    [IntroduceMember(Visibility = PostSharp.Reflection.Visibility.Family, OverrideAction = MemberOverrideAction.Ignore, IsVirtual = true)]
    public double CacheForSeconds { get; set; }


    public MethodCacheAttribute() : this(DefaultCacheSeconds ) { }
    public MethodCacheAttribute(int seconds)
    {
        this.CacheForSeconds = seconds;
    }

    public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
    {
        this.methodName = method.Name;
    }

    public sealed override void OnInvoke(MethodInterceptionArgs args)
    {
        var key = this.BuildCacheKey(args.Arguments,args.Method);

        var item = ServiceLocator.Current.GetInstance<ICacheService>().Cache<object>(key, () =>
            {
                return args.Invoke(args.Arguments);
            },CacheForSeconds ==0 ? TimeSpan.MaxValue :  TimeSpan.FromSeconds(CacheForSeconds));
            args.ReturnValue = item;
    }


    private string BuildCacheKey(Arguments arguments, MethodBase method)
    {
        var sb = new StringBuilder();
        sb.Append(this.methodName);

        foreach (var argument in arguments.ToArray())
        {
            sb.Append(argument == null ? "_" : argument.GetHashCode().ToString());
        }

        if (method.IsGenericMethod)
        {
            var genericArgs = String.Join("-", method.GetGenericArguments().Select(t => t.Name));
            sb.Append(genericArgs);
        }

        return sb.ToString();
    }
}

A rather classic application of the Decorator Pattern is to add caching capabilities. You basically wrap the actual component implementation with another that caches certain type of requests thus improving performance. This is IMO a simple and very elegant approach.

  Component myComponent = new ScientificCalculator();
  Component myDecorator = new ComponentDecorator(myComponent);
  // expensive
  double result = myComponent.doExpensiveComputation();

  // use the Decorator and cache the first time
  result = myDecorator.doExpensiveComputation();
  // and now is cheap
  result = myDecorator.doExpensiveComputation();

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