Ocelot API Gateway Custom Aggregator Issue in ASP.NET Core 3.1

4.8k views Asked by At

I'm implementing custom Aggregator using Ocelot in ASP.NET it's throwing error in Startup.cs Ocelot middleware. However, both Microservices are working fine and fetching the data independently.

When I'm calling them from my API Gateway it's throwing below error.

enter image description here

Startup.cs

public class Startup

{
    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddOcelot()
            .AddSingletonDefinedAggregator<MyAggregator>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public async void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
        await app.UseOcelot();
    }
}

Here is my ocelot.json file for routes of different Microservices.

ocelot.json


{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/user/getUser",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": "44378"
        }
      ],
      "UpstreamPathTemplate": "/getUser",
      "Key": "User"
    },
    {
      "DownstreamPathTemplate": "/product/getProduct",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": "44357"
        }
      ],
      "UpstreamPathTemplate": "/getProduct",
      "Key": "Product"
    }
  ],
  "Aggregates": [
    {
      "ReRouteKeys": [
        "User",
        "Product"
      ],
      "UpstreamPathTemplate": "/UserAndProduct"
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:5000/"
  }
}

My custom aggregator class

MyAggregator.cs


public class MyAggregator : IDefinedAggregator
    {
      
        public async Task<DownstreamResponse> Aggregate(List<HttpContext> responses)
        {
            var one = await responses[0].Items.DownstreamResponse().Content.ReadAsStringAsync();
            var two = await responses[1].Items.DownstreamResponse().Content.ReadAsStringAsync();

            var contentBuilder = new StringBuilder();
            contentBuilder.Append(one);
            contentBuilder.Append(two);

            var stringContent = new StringContent(contentBuilder.ToString())
            {
                Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
            };

            return new DownstreamResponse(stringContent, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "OK");
        }
    }

1

There are 1 answers

2
Ravi On

You forgot to mention your custom aggregator in your ocelot.json file. Ocelot needs to know your custom aggregator whenever you hit /UserAndProduct.

"Aggregates": [ { "ReRouteKeys": [ "User", "Product" ], "UpstreamPathTemplate": "/UserAndProduct" } ]

And there is a breaking change in ocelot's latest version. Use the key Routes instead of ReRoutes. You can use the following json file.

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/user/getUser",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": "44378"
        }
      ],
      "UpstreamPathTemplate": "/getUser",
      "Key": "User"
    },
    {
      "DownstreamPathTemplate": "/product/getProduct",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": "44357"
        }
      ],
      "UpstreamPathTemplate": "/getProduct",
      "Key": "Product"
    }
  ],
  "Aggregates": [
    {
      "RouteKeys": [
        "User",
        "Product"
      ],
      "UpstreamPathTemplate": "/UserAndProduct",
      "Aggregator": "MyAggregator"
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:5000/"
  }
}