c# - ServiceStack.Redis : Configure so that the request and response class/dto is the same class?

标签 c# redis servicestack

一段时间以来,我一直在使用 ServiceStack,我很清楚基于消息的 API 设计是首选,这是我在一些基于 REST 的 API 中使用的东西。

我现在正在研究 Redis/MQ 库,并且一如既往地享受 ServiceStack 的结构和功能。但是,我正在考虑用 MQ 服务器替换一些旧的通信代码,并且有 tested out some SS examples ,而且效果很好。

但是,我正在使用的一些遗留代码对传出请求和响应使用相同的类,例如 GetSomething发送,回复是同一个类的实例GetSomething ,但具有类似 GetSomething.Result 的属性包含回复/结果。

由于我想直接替换当前的通信模型,因此我想看看是否可以“开箱即用”支持这种情况,但我没有真正找到解决此问题的方法。当我在具有处理程序的消费者中出现这样的事情时:

mqHost.RegisterHandler<GetSomething>(base.ExecuteMessage);

以及想要回复的发布者:
mqServer.RegisterHandler<GetSomething>(m => {...});

发生的事情是发布者立即接收请求,并且它永远不会到达消费者。如果我删除发布者中回复的监听器,它会到达消费者,但是当消费者使用相同的 DTO 进行回复时,GetSomething ,它陷入了一个永恒的循环,因为我认为回复被放置在同一个 MQ 队列中。

是否有使用 ServiceStack 解决此问题的聪明方法?

我有一些可能的解决方法的想法,但我想知道这是否可以以更好、更聪明的方式解决。

最佳答案

我只是想分享一种解决方法,它可能不是最漂亮的,但似乎有效。如果有更好的方法来做到这一点,我仍然很感兴趣。

发布者:

发布者为 RedisMqServer 分配一个 RequestFilter,并在该方法中修改 .Body ,用实际请求替换包装器。

然后发布者调用 .RegisterHandler一次用于响应包装器类,然后按预期用于每个实际/真实的处理程序。这将导致调用正确的服务处理程序:

    public RedisClient(string name)
    {
        Name = name;
        redisFactory = new PooledRedisClientManager("localhost:6379");
        mqServer = new RedisMqServer(redisFactory, retryCount: 2);

        mqServer.RequestFilter = RequestFilter;

        // Response wrapper, ContainerResponse implements IProtocolContainer
        mqServer.RegisterHandler<ContainerResponse>(m => 
        {
            return m;
        });

        mqServer.RegisterHandler<GetSomething>(m =>
        {
            // m.Body is here an GetSomething
            return null;
        });
        mqServer.Start();
    }

    private ServiceStack.Messaging.IMessage RequestFilter(ServiceStack.Messaging.IMessage message)
    {
        if (message.Body is IProtocolContainer protocolContainer)
        {
            message.Body = protocolContainer.TheRequest;
        }
        return message;
    }

    public void AddMessage<T>(T theRequest) where T : CoreRequest
    {
        using (var mqClient = mqServer.CreateMessageQueueClient())
        {
            mqClient.Publish(new ContainerRequest(theRequest));
        }
    }
}

消费者:

同样的原则也适用于消费者:
    public override void Configure(Container container)
    {
        container.Register(new ConsumerInfo() { Name = ServiceName });

        var redisFactory = new PooledRedisClientManager("localhost:6379");
        container.Register<IRedisClientsManager>(redisFactory);
        var mqHost = new RedisMqServer(redisFactory, retryCount: 2);

        mqHost.RequestFilter = RequestFilter;
        mqHost.ResponseFilter = ResponseFilter;

        mqHost.RegisterHandler<ContainerRequest>(base.ExecuteMessage);
        mqHost.RegisterHandler<GetSomething>(base.ExecuteMessage);
        mqHost.Start();
    }

    private object ResponseFilter(object arg)
    {
        return new ContainerResponse(arg as CoreRequest);
    }

    private ServiceStack.Messaging.IMessage RequestFilter(ServiceStack.Messaging.IMessage message)
    {
        if (message.Body is IProtocolContainer protocolContainer)
        {
            System.Diagnostics.Debug.WriteLine($"\tReplaced Body with {protocolContainer.TheRequest.GetType().Name}");
            message.Body = protocolContainer.TheRequest;
        }
        return message;
    }
}

关于c# - ServiceStack.Redis : Configure so that the request and response class/dto is the same class?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61621838/

相关文章:

c# - objective-c 是否具有类似于 c# 的泛型类型(和约束)?

c# - 将值传递给 Controller ​​方法时出错

redis - 我如何在 aws 弹性缓存 redis 中异步复制 redis 数据(主从配置)。

spring-boot - 在 Docker 容器中运行的 SpringBoot 应用无法连接到同一台机器上托管的 Redis

.net - Redis 是否提供过期和过期回调?

ServiceStack 使用自定义 AuthUserSession 添加角色和权限

c# - 为什么 C# 使用 [System.Serializable] 来保存实例? (Unity3D)

c# - 如何在 Windows 上使用 Xamarin Studio 开发 iOS 应用程序?

servicestack - 服务栈如何确定可用的服务?

c# - 是否可以使 typescript-ref DTO 生成器尊重可为 null 的属性?