Search code examples
c#.netmicroservicesocelot

Ocelot - Changing the upstream request body in gateway causes no change on downstream request


I'm designing microservice architecture as below:

Microservice architecture

Gateway uses Ocelot to forward requests. I would like to change the body in request received from mobile device on gateway side and add inside the body new GUID. Microservices uses CQRS pattern, so command shouldn't returns anything. I implemented custom middleware to change DownstreamContext:

    public override async Task Execute(DownstreamContext context)
    {
        var secondRequest = JObject.Parse(await context.DownstreamRequest.Content.ReadAsStringAsync());

        secondRequest["token"] = "test";
        secondRequest["newId"] = Guid.NewGuid();

        context.DownstreamRequest.Content = new StringContent(secondRequest.ToString(), Encoding.UTF8);

        await this.Next(context);
    }

I debugged this and content of DownstreamRequest before call await this.Next(context); is changed, but request incoming to microservice is not changed. Is there any way to change request in gateway and forward this request to microservice in a changed form?


Solution

  • You can use for it a custom middleware

    public class SetGuidMiddleware
    {
        private readonly RequestDelegate _next
    
        public SetGuidMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    
        public async Task Invoke(HttpContext context)
        {
            if (!HttpMethods.IsGet(context.Request.Method)
               && !HttpMethods.IsHead(context.Request.Method)
               && !HttpMethods.IsDelete(context.Request.Method)
               && !HttpMethods.IsTrace(context.Request.Method)
               && context.Request.ContentLength > 0)
            {
                //This line allows us to set the reader for the request back at the beginning of its stream.
                context.Request.EnableRewind();
    
                var buffer = new byte[Convert.ToInt32(context.Request.ContentLength)];
                await context.Request.Body.ReadAsync(buffer, 0, buffer.Length);
                var bodyAsText = Encoding.UTF8.GetString(buffer);
    
                var secondRequest = JObject.Parse(bodyAsText);
                secondRequest["token"] = "test";
                secondRequest["newId"] = Guid.NewGuid();
    
                var requestContent = new StringContent(secondRequest.ToString(), Encoding.UTF8, "application/json");
                context.Request.Body = await requestContent.ReadAsStreamAsync();
            }
    
            await _next(context);
        }
    }
    

    and use it before Ocelot

    app.UseMiddleware<SetGuidMiddleware>();
    app.UseOcelot().Wait();