views:

83

answers:

2

I have a WebService that returns a DTO. The webservice gets the data to populate the DTO from an expensive resource. In this simple example, several WebService methods may hit the same ExpensiveResourceProvider method. Where is the best place to perform caching to maximize cache hits? At the webservice or at the ExpensiveResourceProvider? I should note that some data from the ExpensiveResourceProvider changes quite often and should not be cached for long.

public class MyWebService : System.Web.Services.WebService
{
    public MyDTO GetObject1And2()
    {
        MyDTO dto12 = HttpRuntime.Cache.Get("dto12") as MyDTO;
        if(dto12 == null){
            dto12 = new MyDTO();
            dto12.Object1 = ExpensiveResourceProvider.GetObject1();
            dto12.Object2 = ExpensiveResourceProvider.GetObject2();
            HttpRuntime.Cache.Insert("dto12", dto12);
        }
        return dto12;
    }
    public MyDTO GetObject2And3()
    {
        MyDTO dto23 = HttpRuntime.Cache.Get("dto23") as MyDTO;
        if (dto23 == null)
        {
            dto23 = new MyDTO();
            dto23.Object2 = ExpensiveResourceProvider.GetObject2();
            dto23.Object3 = ExpensiveResourceProvider.GetObject3();
            HttpRuntime.Cache.Insert("dto23", dto23);
        }
        return dto23;
    }
    public MyDTO GetObject1And3()
    {
        MyDTO dto13 = HttpRuntime.Cache.Get("dto13") as MyDTO;
        if (dto13 == null)
        {
            dto13 = new MyDTO();
            dto13.Object1 = ExpensiveResourceProvider.GetObject1();
            dto13.Object3 = ExpensiveResourceProvider.GetObject3();
            HttpRuntime.Cache.Insert("dto13", dto13);
        }
        return dto13;
    }
}    
public class ExpensiveResourceProvider
{
    public static object GetObject1() 
    {
        object obj1 = HttpRuntime.Cache.Get("object1") as object;
        if(obj1 == null){
            obj1 = new object();
            HttpRuntime.Cache.Insert("object1", obj1);
        }
        return obj1; 
    }
    public static object GetObject2() 
    {
        object obj2 = HttpRuntime.Cache.Get("object2") as object;
        if (obj2 == null)
        {
            obj2 = new object();
            HttpRuntime.Cache.Insert("object2", obj2);
        }
        return obj2;
    }
    public static object GetObject3()
    {
        object obj3 = HttpRuntime.Cache.Get("object3") as object;
        if (obj3 == null)
        {
            obj3 = new object();
            HttpRuntime.Cache.Insert("object3", obj3);
        }
        return obj3;
    }
}
public class MyDTO
{
    public object Object1 { get; set; }
    public object Object2 { get; set; }
    public object Object3 { get; set; }
}
+1  A: 

The volatility of your data is the key to where to cache it. Depending on your caching mechanism you will have different ways of being notified that your data is stale and it's time to refresh it. Let's assume your caching mechanism provides for supplying a callback delegate, in which case your delegate should live in the same layer as the code that normally populates the cache (preferably the same code that populates the cache to begin with). Having said this it appears that your caching is best left up to your ExpensiveResourceProvider.

Payton Byrd
Stale data is tolerable to a certain extent so I didn't use any callback notification. Normally, I'd just set an absolute expiry of 90 seconds. Next hit after that would force a refresh of that data.
Vince
+1  A: 

Back to the caching basic, you should not consider making decisions of two different layers cache strategy together, they are two different decisions.

For each each layer of a consumer and a service, if you identify the usage pattern that the consumer have very high chance that asking for the same pieces of information within the validity period of the data, then you cache it. If the usage pattern only have remote chance to access the same piece of data within the validity period of the data, don't waste memory and cpu to cache it.

If your web service layer already cached to address the ultimate consumer usage pattern, that mean you resource layer should not be called again within the validity period of data.

However, you web service method doesn't seems to be a good design, which overlapping information with each others. I think your problem is not the caching issue, it's the issue of your DTO object and WS method signature design on how to grouping your data properly.

But in some cases, say each of your web service method need to reference to a reference table at the resource layer. At this point, it's the independent decision at the resource layer which you may decided to cache it at the resource layer.

My two cents...