简体   繁体   English

使用ServiceStack和RabbitMQ发送流

[英]Using ServiceStack and RabbitMQ to send a stream

I am attempting to send a stream using RabbitMQ and Servicestack (v1.0.41 using .NET Core). 我正在尝试使用RabbitMQ和Servicestack(使用.NET Core的v1.0.41)发送流。

My Request implements ServiceStack.Web.IRequiresRequestStream , and the stream property is set in the client, but when it gets to the server, the stream is NULL . 我的请求实现ServiceStack.Web.IRequiresRequestStream ,并且在客户端中设置了流属性,但是当它到达服务器时,流为NULL

Complete Repo 完成回购
Server Code: 服务器代码:

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; }
    }
}

Client Code: 客户代码:

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; }
    }
}

Note: I realise I could just use a byte[] in my request object, but I would quite like to make use of the provided IRequiresRequestStream interface so I can switch back to using HTTP rather than AMQP in the future. 注意:我意识到我可以在请求对象中使用byte [],但是我很想利用提供的IRequiresRequestStream接口,以便将来可以切换回使用HTTP而不是AMQP。

I should also say, that I probably won't be using the RabbitMQ Client provided by servicestack, as I am writing custom logic to convert from HTTP to AMQP, so I will be building the rabbitMQ request manually - the code above just demonstrates the problem I am having in the simplest way possible. 我还应该说,我可能不会使用servicestack提供的RabbitMQ客户端,因为我正在编写自定义逻辑以将HTTP转换为AMQP,因此我将手动构建RabbitMQ请求-上面的代码仅演示了问题我正在以最简单的方式。

I'm going to assume that this won't just work out of the box with AMQP (as it does with HTTP) - so I was thinking that I need to do something like serialize the stream to a byte[] and include it in the RabbitMQ message and then populate the dto which ServiceStack magically re-hydrates on the Server. 我将假设AMQP不能立即使用它(就像HTTP一样)-所以我想我需要做一些事情,例如将流序列化为byte[]并将其包含在其中RabbitMQ消息,然后填充ServiceStack在服务器上神奇地重新水化的dto。

So two questions really... 所以真的有两个问题...
1. Am I on the right track? 1.我走在正确的轨道上吗?
2. If so, how do I hook into the de-serialization code on the server so that I have access to the raw RabbitMQ message in order to convert my byte[] back to a stream and set the stream on my dto? 2.如果是这样,如何连接服务器上的反序列化代码,以便可以访问原始RabbitMQ消息,以便将我的byte []转换回流并在dto上设置流?

You can't send a IRequiresRequestStream Request DTO into a MQ because it's not a normal serialized Request DTO, instead it instructs ServiceStack to skip deserializing the Request DTO and instead inject the HTTP Request Stream so the Service can perform its own Deserialization instead, this is different to a normal Request DTO which is serialized and can be sent as the body in an MQ Message. 您不能将IRequiresRequestStream请求DTO发送到MQ,因为它不是普通的序列化请求DTO,而是指示ServiceStack跳过对请求DTO进行反序列化,而是注入HTTP请求流,以便服务可以执行自己的反序列化,这是与序列化的常规Request DTO不同,该请求DTO可以作为主体在MQ消息中发送。

One option if you want to share implementation between a IRequiresRequestStream Service and a Service that can be called by MQ is to just delegate to a common Service that accepts bytes, eg: 如果要在IRequiresRequestStream服务和MQ可以调用的服务之间共享实现,一种IRequiresRequestStream是仅委托给接受字节的公共服务,例如:

//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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM