使用ServiceStack和RabbitMQ发送流

时间:2017-05-09 12:01:38

标签: c# rabbitmq streaming servicestack amqp

我正在尝试使用RabbitMQ和Servicestack发送流(使用.NET Core v1.0.41)。

我的请求实现了ServiceStack.Web.IRequiresRequestStream,并且在客户端中设置了stream属性,但是当它到达服务器时,流是NULL

完成回购
服务器代码:

using System;
using System.IO;
using System.Threading.Tasks;
using Funq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;
using ServiceStack;
using ServiceStack.Messaging;
using ServiceStack.RabbitMq;
using ServiceStack.Web;

namespace Server
{
    class Program
    {

        public static void Main(string[] args)
        {
            IWebHost host = new WebHostBuilder()
                .UseServer(new RabbitServer())
                .UseStartup<Startup>()
                .Build();

            host.Run();
        }
    }

    public class RabbitServer : IServer
    {
        public void Dispose(){}

        public void Start<TContext>(IHttpApplication<TContext> application){}

        public IFeatureCollection Features { get; } = new FeatureCollection();
    }

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddLogging();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseServiceStack((AppHostBase)Activator.CreateInstance<AppHost>());
            app.Run((RequestDelegate)(context => (Task)Task.FromResult<int>(0)));
        }

    }

    public class AppHost : AppHostBase
    {
        public AppHost()
            : base("My Test Service", typeof(MyService).GetAssembly())
        {
        }

        public override void Configure(Container container)
        {
            var mqServer = new RabbitMqServer("127.0.0.1");
            container.Register<IMessageService>(mqServer);
            mqServer.RegisterHandler<HelloRequest>(ExecuteMessage);
            mqServer.Start();
        }
    }

    public class MyService : Service
    {
        public HelloResponse Any(HelloRequest request)
        {
            Console.WriteLine($"Stream is null: {request.RequestStream == null}");
            return new HelloResponse { Counter = request.Counter };

        }
    }

    public class HelloRequest : IReturn<HelloResponse>, IRequiresRequestStream
    {
        public int Counter { get; set; }

        public Stream RequestStream { get; set; }
    }

    public class HelloResponse
    {
        public int Counter { get; set; }
    }
}

客户代码:

using ServiceStack;
using ServiceStack.Messaging;
using ServiceStack.RabbitMq;
using ServiceStack.Web;
using System;
using System.IO;
using System.Text;

namespace Client
{
    class Program
    {

        static void Main(string[] args)
        {
            RabbitMqServer messageService = new RabbitMqServer("127.0.0.1");
            RabbitMqQueueClient mqClient = messageService.MessageFactory.CreateMessageQueueClient() as RabbitMqQueueClient;
            var responseQueueName = mqClient.GetTempQueueName();
            MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("Hello World!")) { Position = 0 };
            HelloRequest request = new HelloRequest { Counter = 100, RequestStream = ms };  //Counter is just some arbitary extra data
            Guid messageId = Guid.NewGuid();

            mqClient.Publish(QueueNames<HelloRequest>.In, new Message<HelloRequest>(request) { ReplyTo = responseQueueName, Id = messageId });
        }
    }

    public class HelloRequest : IReturn<HelloResponse>, IRequiresRequestStream
    {
        public int Counter { get; set; }
        public Stream RequestStream { get; set; }
    }

    public class HelloResponse
    {
        public int Counter { get; set; }
    }
}

注意:我意识到我可以在我的请求对象中使用byte [],但我非常想使用提供的IRequiresRequestStream接口,所以我可以切换回使用HTTP而不是AMQP未来。

我还应该说,我可能不会使用servicestack提供的RabbitMQ客户端,因为我正在编写自定义逻辑以从HTTP转换为AMQP,所以我将手动构建rabbitMQ请求 - 上面的代码只是以最简单的方式展示我遇到的问题。

我将假设这不仅仅是AMQP的开箱即用(就像HTTP一样) - 所以我想我需要做一些事情,比如将流序列化为{{1}并将其包含在RabbitMQ消息中,然后填充服务器上的ServiceStack神奇地重新保存的dto。

真的有两个问题...... 1.我是否走在正确的轨道上? 2.如果是这样,我如何挂钩服务器上的反序列化代码,以便我可以访问原始RabbitMQ消息,以便将我的byte []转换回流并在我的dto上设置流?

1 个答案:

答案 0 :(得分:2)

您不能将IRequiresRequestStream请求DTO发送到MQ,因为它不是正常的序列化请求DTO,而是指示ServiceStack跳过反序列化请求DTO,而是注入HTTP请求流,以便服务可以执行相反,它与正常的Request DTO不同,后者是序列化的,可以作为MQ消息中的正文发送。

如果要在IRequiresRequestStream服务和可由MQ调用的服务之间共享实现,则只需委托一个接受字节的公共服务,例如:

//Called from HTTP
public object Any(HelloStream request) => 
    Any(new HelloBytes { Bytes = request.RequestStream.ReadFully() });

//Called from HTTP or MQ
public object Any(HelloBytes request) 
{
    //= request.Bytes
}