Caching with ToOptimzedRsultUsingCache()

OK, I’ve been implementing a new caching pattern that utilizes the ToOptimzedRsultUsingCache() method in my service operations.

Now, I am not sure I fully understand what it is that this method returns, although I know it is not a regular DTO, but some CompressedResult of some kind, and how that is sent over the wire and understood by a client I don’t fully understand yet.

But it seems to work fine with service operations that return DTO’s, except when I return it from a service operation that returns a Stream, like this one:

    [AddHeader(ContentType = MimeTypes.ImagePng)]
    public object Get(GetPngPic body)
        var cacheKey = "....";
        return Request.ToOptimizedResultWithCache(CacheClient, cacheKey, ()=>{
            // Code to fetch an image from blob storage and return it as a System.IO.Stream.

I get a 400 Bad Request exception thrown from the service, when called from my JsonServiceClient using url.GetBytesFromUrl()

Do I have to handle Streams differently or something?

The ToOptimized* API’s only works with serializable Response DTO’s, i.e. you can’t use them on streams or other custom Http Results. BTW you also don’t want to apply compression (ToOptimizedResult implicitly adds) on existing compressed binary formats like images where compression makes it worse, yielding larger payload + more CPU.

Ah, OK, needed to learn that.
Caching images still a good thing for a REST service though I think.

Am I rolling my own pattern for images then? and should I doing a similar thing as ToOptimizedResultWithCache() and returning some kind of compressedResult or just the raw cached bytes?

You don’t want to compress images, personally I wouldn’t cache large images in a ICacheClient either, which usually end up taking a lot of memory. My preference would be to store them in something like S3 and return a url to the location so a native web server can serve them directly, S3 ends up being a lot more efficient then serving images through ASP.NET and adds the appropriate caching headers.

If you’re not in the cloud, I would save them to disk and still return a url so the static file handler can serve them like a regular file (which also takes care of adding HTTP caching headers).

Also if you have a chance to write them somewhere and have a native web server like nginx or IIS serve them, that’s even better as they can be pretty resource intensive writing them to the response in managed code. But it’s ok if you don’t have to handle a lot of load.

Thanks, we actually store the image URLS in other objects, and don’t ever include the bytes in any responses. Clients deal with the URLs (at various image resolutions), but at some point a client will need to drag down and display an image (e.g. on a web page), and that image is never going to change, so might be worth caching (I thought).

But on reflection, your point about caching them is right on, the call to fetch the bytes from the backend is actually no different (well marginally) from returning it from a cache on our service. We are in the cloud and store everything in Azure tables at this point, although we will probably use AzureRedis for our CacheClient.

Conceded, the HTTP reverse proxies can cache what they wish (so we will tell them it is cacheable for an hour at least), our service will not cache them in memory though.