c#中用lua脚本执行redis命令

直接贴出代码,实现执行lua脚本的方法,用到的第三方类库是 StackExchange.Redis(nuget上有)

注:下面的代码是简化后的,实际使用要修改,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using StackExchange.Redis;


namespace TL.Cloud.KV
{
    public class Kv:IKv
    {
       
       
        private  ConfigurationOptions _redisConfig;// = new ConfigurationOptions
        private  IDatabaseAsync _db;//=Connection.GetDatabase();
        private  IServer _server;// = GetServer();
        private  string _keyPrefix;// 区分前缀

        /// <summary>
        /// 每个微服务一个kv云实例,或共享云实例中(无独立前缀,服务间Key取名需要自行防止冲突)
        /// </summary>
        /// <param name="hostServiceName">宿主微服务</param>
        public Kv(PublicCloudKvConfig config)
        {
            Init(config);
        }

        private void Init(PublicCloudKvConfig config)
        {
            //独特的区分dev/100前缀,online可以没有
            _keyPrefix = string.IsNullOrWhiteSpace(config.KeyPrefix)
                ?null
                :config.KeyPrefix.Trim().ToLower()+':';//小写带冒号分割
            //ali kv
            var kvUrl = config.KvUrl;


            _redisConfig = ConfigurationOptions.Parse(kvUrl);
           
            _redisConfig.Password = config.KvPassword;
            _redisConfig.SetDefaultPorts(); //自动填充默认端口
            var connection = ConnectionMultiplexer.Connect(_redisConfig);
            _db = connection.GetDatabase();
            _server = GetServer();
            
        }

        private  IServer GetServer()
        {
            var config = new ConfigurationOptions
            {
                KeepAlive = 0,
                EndPoints = { _redisConfig.EndPoints[0]},
                AbortOnConnectFail = false,
                AllowAdmin = true
            };
            var conn = ConnectionMultiplexer.Connect(config);
            return conn.GetServer(config.EndPoints[0]);
        }

        public Task<RedisResult> EvalLua(string lua, IList<RedisKey> keys, IList<RedisValue> values)
        {
            if (_keyPrefix != null)
                keys = keys.Select(p => p.Prepend(_keyPrefix)).ToList();//加上前缀
            return _db.ScriptEvaluateAsync(lua, keys.ToArray(), values.ToArray());
        }
        

        public async Task<RedisResult> EvalLua(byte[] luaSha1, IList<RedisKey> keys, IList<RedisValue> values)
        {
            if (_keyPrefix != null)
                keys = keys.Select(p => p.Prepend(_keyPrefix)).ToList();//加上前缀
            return await _db.ScriptEvaluateAsync(luaSha1, keys.ToArray(), values.ToArray());
        }
        
      

        public async Task<byte[]> LoadLuaToServerAsync(string lua)
        {
            var sha1 = lua.CalcLuaSha1();//本地计算
            if(!await _server.ScriptExistsAsync(sha1))//服务器上不存在
                 sha1 = await _server.ScriptLoadAsync(lua);//应该和计算的相同
                
            return sha1;
        }
    }
}

下面是测试代码段

//下面是测试代码
        [Test]
        public async Task LoadLuaToServerAsync()
        {
            var key = "TestEvalLua10010";
            var fieldContent = "testlua10011";
            const string lua =
                "redis.call('SET', KEYS[1], ARGV[1])\n" +
                "return redis.call('GET', KEYS[1])\n";

            var sha2 = lua.CalcLuaSha1();
            var sha1 = await _kv.LoadLuaToServerAsync(lua);
            Assert.AreEqual(20, sha1.Length);
            for (var i = 0; i < 20; i++)
                Assert.AreEqual(sha1[i],sha2[i]);
            
            var keys = new List<RedisKey> { key };
            var values = new List<RedisValue> { fieldContent };
            var result = await _kv.EvalLua(sha1, keys, values);
            Assert.AreEqual(fieldContent, (string)result);
        }

计算sha1用到的方法

//计算lua的sha1结果,作为执行lua的参数
        public  static byte[] CalcLuaSha1(this string lua)
        {
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            var bytesSha1In = Encoding.Default.GetBytes(lua);
            return sha1.ComputeHash(bytesSha1In);
        }