Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the Best Practice to configure StackExchange.Redis with Autofac?

In the StackExchange.Redis docs it is recommended to only create one and reuse the connection to Redis.

Azure Redis best practices recommends using the following pattern:

private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
    return ConnectionMultiplexer.Connect("cachename.redis.cache.windows.net,ssl=true,abortConnect=false,password=password");
});

public static ConnectionMultiplexer Connection
{
    get
    {
        return lazyConnection.Value;
    }
}

but how should I get this working with Autofac where I want the configuration to be set in the web/app config files?

I currently have a RedisCacheProvider:

private readonly ConnectionMultiplexer _connection;

public RedisCacheProvider(string config)
{
    _connection = ConnectionMultiplexer.Connect(config);
}

and in my Autofac config:

builder.RegisterType<RedisCacheProvider>().As<ICacheProvider>().WithParameter("config", "localhost");

My thinking is, I should change my RedisCacheProvider to take in a ConnectionMultiplexer which is passed in via the static variable?

Update: My Solution so far:

My RedisCacheProvider (injecting an interface here allows me to mock the connection in unit tests):

private readonly IConnectionMultiplexer _connection;

public RedisCacheProvider(IConnectionMultiplexer connection)
{
   _connection = connection;
}

RedisConnection class to hold the static property and read config from config file:

public class RedisConnection
{
    private static readonly Lazy<ConnectionMultiplexer> LazyConnection = 
        new Lazy<ConnectionMultiplexer>(
            () => ConnectionMultiplexer.Connect(ConfigurationManager.AppSettings["RedisCache"]));

    public static ConnectionMultiplexer Connection
    {
        get
        {
            return LazyConnection.Value;
        }
    }
}

Registration in an Autofac Module:

builder.RegisterType<RedisCacheProvider>().As<ICacheProvider>()
                    .WithParameter(new TypedParameter(
                                       typeof(IConnectionMultiplexer), 
                                       RedisConnection.Connection));
like image 237
EdmundYeung99 Avatar asked Jul 16 '15 23:07

EdmundYeung99


People also ask

Is StackExchange Redis thread safe?

redis is fully thread safe; the expected usage is that a single multiplexer is reused between concurrent requests etc - very parallel. Two concurrent callers do not block each other: the two requests are pipelined and the results made available to each when the come back.

What is Redis ConnectionMultiplexer?

Redis is the ConnectionMultiplexer class in the StackExchange. Redis namespace; this is the object that hides away the details of multiple servers. Because the ConnectionMultiplexer does a lot, it is designed to be shared and reused between callers. You should not create a ConnectionMultiplexer per operation.

What is Redis connection timeout?

Anytime, when client application doesn't receive response before one of the timeout values expire, a timeout will occur and will be logged on client application logs as Redis timeout error message.

What is Redis StackExchange?

Overview. StackExchange. Redis is a high performance general purpose redis client for . NET languages (C#, etc.). It is the logical successor to BookSleeve, and is the client developed-by (and used-by) Stack Exchange for busy sites like Stack Overflow.


1 Answers

Autofac supports Implicit Relationship Types and Lazy<> evaluation is supported out of the box. So after you register your RedisCacheProvider as in your example, that is

builder
.RegisterType<RedisCacheProvider>()
.As<ICacheProvider>()
.WithParameter("config", "localhost");

you can resolve it like below:

container.Resolve<Lazy<ICacheProvider>>();

But do not forget that default Autofac lifetime scope is InstancePerDependency(transient). That is, you will get new instance of RedisCacheProvider everytime you resolve it or whenever it is provided to other component as dependency. To fix this you need to specify its lifetime scope explicitly. For instance, to make it singleton you need to change registration as below:

builder
.RegisterType<RedisCacheProvider>()
.As<ICacheProvider>()
.WithParameter("config", "localhost")
.SingleInstance();

Another assumption here is that RedisCacheProvider is the only component where Redis connection is used. If it is not the case then you should better let Autofac manage Redis connection's life scope (which is a better idea anyway) and get the connection as a dependency in RedisCacheProvider. That is:

public RedisCacheProvider(IConnectionMultiplexer connection)
{
    this.connection = connection;
}

....

builder
.Register(cx => ConnectionMultiplexer.Connect("localhost"))
.As<IConnectionMultiplexer>()
.SingleInstance();

builder
.RegisterType<RedisCacheProvider>()
.As<ICacheProvider>();
like image 192
Vitaliy Tsvayer Avatar answered Oct 06 '22 09:10

Vitaliy Tsvayer