Jaxelr / Nancy.RapidCache

A library to asynchronously cache responses on NancyFx Modules.
MIT License
6 stars 2 forks source link
cache couchbase nancyfx redis

Nancy.RapidCache Mit License

Cache content asynchronously inside NancyFx. Allows you to set a timespan of lifecycle for your cache. Also allows to redefine the desired Cache backend and desires key request. By default it provides a default memory cache and a default uri key.

Note: Since Nancyfx is no longer being maintained i will be deprioritizing this library, please check here for details

Builds

This library targets Nancyfx 2 and above.

Appveyor Branch Coverage
Build status master CodeCov
Build status develop CodeCov

Packages

Package NuGet (Stable) MyGet (Prerelease)
Nancy.RapidCache NuGet MyGet
Nancy.RapidCache.Redis NuGet MyGet
Nancy.RapidCache.Couchbase NuGet MyGet
Nancy.RapidCache.IMemory NuGet MyGet

Installation

Install via nuget https://nuget.org/packages/Nancy.RapidCache

PM> Install-Package Nancy.RapidCache

Sample usage

The following example is using the default "In-Memory" CacheStore which is nothing more than a concurrent dictionary.

  1. Add to your Nancy bootstrapper
using Nancy.RapidCache.Extensions;
using Nancy.Routing;

namespace WebApplication
{
    public class ApplicationBootrapper : Nancy.DefaultNancyBootstrapper
    {
        protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);
            /* Enable rapidcache, vary by url, query, form and accept header */
            this.EnableRapidCache(container.Resolve<IRouteResolver>(), ApplicationPipelines, new[] { "query", "form", "accept" });
        }
    }
}
  1. Enable caching by adding the "AsCacheable" extension method to any of your routes
using System;
using Nancy;
using Nancy.RapidCache.Extensions;

namespace WebApplication
{
    public class ExampleModule : NancyModule
    {
        public ExampleModule()
        {
            Get("/", _ =>
            {
                /* cache view for 30 secs */
                return View["hello.html"].AsCacheable(DateTime.Now.AddSeconds(30));
            });

            Get("/CachedResponse", _ =>
            {
                /* cache response for 30 secs */
                return Response.AsText("hello").AsCacheable(DateTime.Now.AddSeconds(30));
            });
        }
    }
}

Or alternatively, set the Cache on all requests by using an after request on the start of the pipeline.

using Nancy.RapidCache.Extensions;
using Nancy.Routing;

namespace WebApplication
{
    public class ApplicationBootrapper : Nancy.DefaultNancyBootstrapper
    {
        protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);
            /* Enable RapidCache, vary by url params query, form and accept headers */
            this.EnableRapidCache(container.Resolve<IRouteResolver>(), ApplicationPipelines, new[] { "query", "form", "accept" });
            pipelines.AfterRequest.AddItemToStartOfPipeline(ConfigureCache);
        }

        public void ConfigureCache(NancyContext context)
        {
            /* Cache all responses by 30 seconds with status code OK */
            context.Response = context.Response.AsCacheable(DateTime.Now.AddSeconds(30));
        }
    }
}

Keep in mind that for Post* methods, the requests body is NOT part of the key in this scenario. In context, you can filter by the values of:

Using Different Cache Stores

DiskCacheStore

When using Nancy in self hosting mode, you can use the DiskCacheStore to enable caching throught RapidCache to a tmp file.

using Nancy.RapidCache.CacheStore;
using Nancy.RapidCache.Extensions;
using Nancy.Routing;

namespace WebApplication
{
    public class ApplicationBootrapper : Nancy.DefaultNancyBootstrapper
    {
        protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);
            /* Enable RapidCache using the DiskCacheStore, vary by url params id,query,takem, skip and accept header */
            this.EnableRapidCache(container.Resolve<IRouteResolver>(), ApplicationPipelines, new[] { "query", "form", "accept" }, new DiskCacheStore("c:/tmp/cache"));
        }
    }
}

IMemoryCacheStore

One of the lightweight alternatives to the MemoryCacheStore which is included as part of the RapidCache library is the external IMemoryCacheStore, which requires a separate nuget lib installation:

PM> Install-Package Nancy.RapidCache.IMemory

the difference being that the store uses the Microsoft.Extensions.Caching.Memory as a dependency. The declaration is the same, simply replacing the previous one:

namespace WebApplication
{
    public class ApplicationBootrapper : Nancy.DefaultNancyBootstrapper
    {
        protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);
            /* Enable cache using the IMemoryCacheStore, which uses the MsCaching Memory library, using the same key variations */
            this.EnableRapidCache(container.Resolve<IRouteResolver>(), ApplicationPipelines, new[] { "query", "form", "accept" }, new IMemoryCacheStore());
        }
    }
}

RedisCacheStore

RapidCache provides a small lib for integration with Redis, given that you provide a valid connection. It is provided as a separate package, so install it first via nuget:

PM> Install-Package Nancy.RapidCache.Redis

the usage is similar to the other stores:

using Nancy.RapidCache.CacheStore;
using Nancy.RapidCache.Extensions;
using Nancy.Routing;

namespace WebApplication
{
    public class ApplicationBootrapper : Nancy.DefaultNancyBootstrapper
    {
        protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);
            /* Enable RapidCache using the RedisCacheStore, vary by url params id,query,takem, skip and accept header */
            this.EnableRapidCache(container.Resolve<IRouteResolver>(), ApplicationPipelines, new[] { "query", "form", "accept" }, new RedisCacheStore("localhost"));
        }
    }
}

CouchbaseCacheStore

RapidCache also provides a small lib for a integration with Couchbase, given that you provide a valid Cluster object from the CouchbaseNetClient package and a bucket name that can be located. Install it via nuget:

PM> Install-Package Nancy.RapidCache.Couchbase

Once installed, we need to configure the cluster first, and then pass the cluster to the constructor:

using Nancy.RapidCache.CacheStore;
using Nancy.RapidCache.Extensions;
using Nancy.Routing;

namespace WebApplication
{
    public class ApplicationBootrapper : Nancy.DefaultNancyBootstrapper
    {
        protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);

            var cluster = new Cluster(new ClientConfiguration
            {
                Servers = new List<Uri> { new Uri("http://127.0.0.1") }
            });

            var authenticator = new PasswordAuthenticator("user", "password");
            cluster.Authenticate(authenticator);

            /* Enable RapidCache using the CouchbaseCacheStore, vary by url params id,query,takem, skip and accept header */
            /* Provide a bucket on the configuration */
            this.EnableRapidCache(container.Resolve<IRouteResolver>(), ApplicationPipelines, new[] { "query", "form", "accept" }, new CouchbaseCacheStore(cluster, "myBucket")));
        }
    }
}

Definining your own cache key generation using ICacheKeyGenerator

Define your own key per resolver that will help you cache to the level of granulatity you need.

using System;
using System.Text;
using Nancy;
using Nancy.RapidCache.Extensions;
using Nancy.Routing;

namespace WebApplication
{
    public class ApplicationBootrapper : Nancy.DefaultNancyBootstrapper
    {
        protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);
            this.EnableRapidCache(container.Resolve<IRouteResolver>(), ApplicationPipelines, new UrlHashKeyGenerator());
        }

        public class UrlHashKeyGenerator : Nancy.RapidCache.CacheKey.ICacheKeyGenerator
        {
            public string Get(Request request)
            {
                using (var md5 = MD5.Create())
                {
                    byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(request.Url.ToString()));
                    return Convert.ToBase64String(hash);
                }
            }
        }
    }
}

For more details please check the documentation.