본문 바로가기

TroubleShooting/C#

C# Redis Client - StackExchange.Redis.Extensions

728x90

 C# 에서 Redis 에 데이터를 저장하고 가져오기 위해서 찾아본 라이브러리 중에서 "CloudStructers" 가 있었다. 간편한 사용법에 클래스를 serialze/desirialize 할 수있고, async 가 지원된다는 장점이 있다. 그외 Rx 도 같이 되는거 같은데, 깃허브에 관련 내용이 있다. 

 클래스를 Redis Hash 구조체로 만들어주는 RedisClass<> 가 있어서 프로젝트에 이용하려고 테스트 예제를 짜는데, 원 클래스를 상속받은 자식클래스 인스턴스를 선언하고 (부모클래스에 있는 모든)멤버 변수에다가 값을 저장후 Redis 에 저장해보니 제대로 동작을 안한다.

- 소스

 public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    public class Child : Person
    {
        public int Sex { get; set; } 
        public string LastName { get; set; }
    }

    [TestClass]
    public class UnitTest2
    {
        public static readonly RedisSettings redisSetting = new RedisSettings("IP");

        [TestMethod]
        public void TestMethod1()
        {
            var redisObj = new RedisString

(redisSetting, "idid"); Child child = new Child(); child.Name = "Alice"; child.Age = 18; child.Sex = 1; redisObj.Set(child); } }

 Person 클래스를 상속받은 Child 클래스 인스턴스를 생성하고 값을 저장하고 Redis 로 Set 를 했는데, 실제 Redis 서버에 저장된 내용은 Child 의 멤버 변수만 저장이 된다.

127.0.0.1:6379> get idid

"\xef\xbb\xbf{\"Sex\":1,\"LastName\":null}"


 원인을 분석해보려고 깃허브에 올라온 소스를 확인해보니깐, ValueConverter.Serialize() 에서 문제가 되는듯해서, ValueConverter 를 보니, JSON serialize 라이브러인 Jil 을 사용하는 부분에서 subclass 까지 Serialzie 하는 SerializeDynamic() 을 이용안해서 이런 문제가 발생한듯했다.(https://github.com/kevin-montrose/Jil#dynamic-serialization)

- RedisString.cs

/// /// SET http://redis.io/commands/set
/// 
public Task Set(T value, RedisExpiry expiry = null, When when = When.Always, CommandFlags commandFlags = CommandFlags.None)
{
    return TraceHelper.RecordSendAndReceive(Settings, Key, CallType, async () =>
    {
        long sentSize;
        var v = Settings.ValueConverter.Serialize(value, out sentSize);

        bool r;
        if (expiry != null && expiry.IsTimeSpan)
        {
            r = await Command.StringSetAsync(Key, v, (TimeSpan)expiry.Value, when, CommandFlags.None).ForAwait();
        }
        else
        {
            r = await this.ExecuteWithKeyExpire(x => x.StringSetAsync(Key, v, expiry: null, when: when, flags: commandFlags), Key, expiry, commandFlags).ForAwait();
        }

        return Tracing.CreateSentAndReceived(new { value, expiry, when }, sentSize, r, sizeof(bool));
    });
}

소스를 받아서 수정해야하나 고민하다가, 다른 라이브러리를 찾아보다가 "CloudStructers" 가 이용하는 "StackeExchange.Redis" 를 알아보았다. StackExchange 도 pipeline 기능도 지원해서(async 도 지원), 간단 예제를 작성해보니 쉽게 사용할 수 있었을 거 같았다. Redis 의 여러 자료구조들은 다 지원을 하는데, 클래스 단위로 저장할 수 있는 방법은 없은거 같아서 다시 찾아보니, "StackExchange.Redis.Extension" 이 있었다.


     - 테스트 유닛 소스

    public class Person2
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    public class Child2 : Person2
    {
        public int Sex { get; set; }
        public string LastName { get; set; }
    }

    [TestClass]
    public class UnitTestStackExchange
    {
        [TestMethod]
        public void TestMethod1()
        {
            ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("IP");
            IDatabase db = redis.GetDatabase(0, null);

            db.StringSet("mykey", "abcdef");

            string value = db.StringGet("mykey");
            Console.WriteLine("Value:" + value);
        }

        [TestMethod]
        public void TestMethod2()
        {
            var serializer = new NewtonsoftSerializer();
            var cacheClient = new StackExchangeRedisCacheClient(serializer);

            Child2 child = new Child2();
            child.Name = "Alice";
            child.Age = 18;
            child.Sex = 1;
            cacheClient.Add("my-key", child);
        }

      - App.config : StackExchangeRedisCacheClient() 파라미터로 넘기는 serializer 를 App.config 를 통해서 설정하고 컨테이너에 등록해야한다.

<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="redisCacheClient" type="StackExchange.Redis.Extensions.Core.Configuration.RedisCachingSectionHandler, StackExchange.Redis.Extensions.Core" /> </configSections> <redisCacheClient allowAdmin="true" ssl="false" connectTimeout="5000" database="0"> <hosts> <add host="IP" cachePort="6379"/> </hosts> </redisCacheClient> </configuration>



참조 사이트 :

- CloudStructures.Redis

https://github.com/neuecc/CloudStructures


- Jil

https://github.com/kevin-montrose/Jil


- StackExchane.Redis 사용 예제 블로그

http://tostring.it/2015/04/23/An-easy-way-to-use-StackExchange-Redis%20copy/


- StackExchange.Redis.Extension

https://github.com/imperugo/StackExchange.Redis.Extensions


'TroubleShooting > C#' 카테고리의 다른 글

excel2json 자바스크립트  (0) 2015.08.12
DateTime 값으로 Tick 값을 구하는 C# 코드  (0) 2013.11.13