Building API Gateway Using Ocelot In ASP.NET Core - Service Discovery (Eureka)

Introduction

In the previous articles of this series, we discussed how to build the API Gateway in ASP.NET Core.

And in this article, we will discuss service discovery module of Ocelot with Spring Cloud Eureka Server.

If you want to look at the previous articles of this series, please visit the links given below.

What is Service Discovery?

Service discovery is the automatic detection of devices and services offered by these devices on a computer network. A service discovery protocol (SDP) is a network protocol that helps accomplish service discovery. Service discovery aims to reduce the configuration efforts from users.

There are some types of service discovery we can use in Ocelot, such as Consul, Eureka, and so on. In this article, I will show you the usage with Eureka. Ocelot uses Steeltoe to communicate with Eureka, which is an open source project that enables .NET developers to implement industry standard best practices when building resilient microservices for the cloud.

I will use version 7.1.0-unstable0011 of Ocelot to show you this feature.

Step 1 

We are creating two API services at first. Just create the default ASP.NET Core Web API project. Before API gateway can discover our API Services, we need to register them in Eureka Server.

Add some configuration in appsettings.json.
  1. "spring": {  
  2.     "application": {  
  3.         "name""service-a"  
  4.     }  
  5. },  
  6. "eureka": {  
  7.     "client": {  
  8.         "serviceUrl""http://192.168.0.107:8761/eureka/",  
  9.         "shouldFetchRegistry"true,  
  10.         "validateCertificates"false  
  11.     },  
  12.     "instance": {  
  13.         "port": 9001,  
  14.         "instanceId""192.168.0.103:9001",  
  15.         "hostName""192.168.0.103",  
  16.         "healthCheckUrlPath""/api/values/healthcheck",  
  17.         "statusPageUrlPath""/api/values/info"                  
  18.     }  
  19. }  
Note
  1. Service-a is an important part that ocelot will use it to find out this service.
  2. ServiceUrl is the endpoint of the Eureka Server.
  3. For more information of each item, you can visit here.
Add some code to enable service discovery.
  1. public class Startup  
  2. {  
  3.     public Startup(IConfiguration configuration)  
  4.     {  
  5.         Configuration = configuration;  
  6.     }  
  7.   
  8.     public IConfiguration Configuration { get; }  
  9.   
  10.     public void ConfigureServices(IServiceCollection services)  
  11.     {  
  12.         services.AddDiscoveryClient(Configuration);  
  13.         services.AddMvc();  
  14.     }  
  15.   
  16.     public void Configure(IApplicationBuilder app, IHostingEnvironment env)  
  17.     {  
  18.         if (env.IsDevelopment())  
  19.         {  
  20.             app.UseDeveloperExceptionPage();  
  21.         }  
  22.   
  23.         app.UseDiscoveryClient();  
  24.         app.UseMvc();  
  25.     }  
  26. }  

Here, I will use three API Services to show, two API services name service-a with different port (9001 and 9003), one API service name service-b.

Step 2 

Create an APIGateway project. And add a json configuration file named ocelot.json. 
  1. {  
  2.     "ReRoutes": [  
  3.         {  
  4.             "DownstreamPathTemplate""/api/values",  
  5.             "DownstreamScheme""http",  
  6.             "UpstreamPathTemplate""/a",  
  7.             "UseServiceDiscovery"true,  
  8.             "ServiceName""service-a",  
  9.             "UpstreamHttpMethod": [ "Get" ],  
  10.             "QoSOptions": {  
  11.                 "ExceptionsAllowedBeforeBreaking": 3,  
  12.                 "DurationOfBreak": 1000,  
  13.                 "TimeoutValue": 5000  
  14.             },  
  15.             "FileCacheOptions": { "TtlSeconds": 15 },  
  16.             "LoadBalancerOptions": {  
  17.                 "Type""RoundRobin"  
  18.             }  
  19.         },  
  20.         {  
  21.             "DownstreamPathTemplate""/api/values",  
  22.             "DownstreamScheme""http",  
  23.             "UpstreamPathTemplate""/b",  
  24.             "UseServiceDiscovery"true,  
  25.             "ServiceName""service-b",  
  26.             "UpstreamHttpMethod": [ "Get" ],  
  27.             "QoSOptions": {  
  28.                 "ExceptionsAllowedBeforeBreaking": 3,  
  29.                 "DurationOfBreak": 1000,  
  30.                 "TimeoutValue": 5000  
  31.             },  
  32.             "FileCacheOptions": { "TtlSeconds": 15 }  
  33.         }  
  34.     ],  
  35.     "GlobalConfiguration": {  
  36.         "RequestIdKey""OcRequestId",  
  37.         "AdministrationPath""/administration",  
  38.         "ServiceDiscoveryProvider": { "Type""Eureka" }  
  39.     }  
  40. }  
There are some items we need to pay attention to.

For ReRoutes,
  1. Set UseServiceDiscovery to true;
  2. Set ServiceName to service's name that define in API service.
  3. Do not specify the DownstreamHostAndPorts
  4. Set type of LoadBalancerOptions to RoundRobin.
For GlobalConfiguration

Just specify the ServiceDiscoveryProvider. Set the type to Eureka. This is a very very important configuration to use Eureka!!

Turning to Program.cs, we need to enable Ocelot!!
  1. public class Program  
  2. {  
  3.     public static void Main(string[] args)  
  4.     {  
  5.         BuildWebHost(args).Run();  
  6.     }  
  7.   
  8.     public static IWebHost BuildWebHost(string[] args) =>  
  9.         WebHost.CreateDefaultBuilder(args)  
  10.            .UseUrls("http://*:9000")  
  11.            .ConfigureAppConfiguration((hostingContext, config) =>  
  12.             {  
  13.                 config  
  14.                     .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)                        
  15.                     .AddJsonFile("ocelot.json")  
  16.                     .AddEnvironmentVariables();  
  17.             })  
  18.            .ConfigureServices(s =>  
  19.             {  
  20.                 s.AddOcelot();  
  21.             })  
  22.             .Configure(a =>  
  23.             {  
  24.                 a.UseOcelot().Wait();  
  25.             })  
  26.             .Build();  
  27. }  
Step 3

Let's run up the Eureka Server.
 
ASP.NET Core 

As you can see, the Eureka Server is up but there are no instances available.

Note

For running the Eureka server in your computer, you can try the following steps.
  1. Install Java 8 JDK.
  2. Install Maven 3.x.
  3. Clone the Spring Cloud Samples Eureka repository. (https://github.com/spring-cloud-samples/eureka.git)
  4. Go to the eureka server directory (eureka) and fire it up with mvn spring-boot:run
Step 4 

How can we register our services? Just run up our project! We will take service-a for example.

After running up API service, we can find that service-a is up in Eureka server!

ASP.NET Core

Now, let's run the API Gateway. Unfortunatelly, at this time we can run up our API Gateway.

ASP.NET Core

Based on the exception message, we forget to config the Eureka in the API Gateway project. Add the configuration in appsettings.json.
  1. "spring": {  
  2.     "application": {  
  3.         "name""service-gw"  
  4.     }  
  5. },  
  6. "eureka": {  
  7.     "client": {  
  8.         "serviceUrl""http://192.168.0.107:8761/eureka/",  
  9.         "shouldRegisterWithEureka"false,  
  10.         "validateCertificates"false  
  11.     },  
  12.     "instance": {  
  13.         "port": 9000,  
  14.         "instanceId""192.168.0.103:9000",  
  15.         "hostName""192.168.0.103"  
  16.     }  
  17. }  

Run the API Gateway again. It runs well now.

ASP.NET Core
 
Visit service-a via API Gateway.

ASP.NET Core

Visit service-b via API Gateway which we do not run  up yet.

ASP.NET Core

There is no doubt that we cannot access service-b.

After running up:

ASP.NET Core

Visit again.
 
ASP.NET Core

It can be accessed now.

At last, register another service-a.

ASP.NET Core

Visit service-a, sometimes you will get the result from 9001 and sometimes from 9003, because we use RoundRobin LoadBalancer.

ASP.NET Core

And when we stop one of service-a, we can still visit it, and it will not visit the break service.

Here is the source code you can find in my github page .

APIGatewaySDDemo

Summary

This article introduced the basic usage of service discovery with Eureka in Ocelot.

You can also use this feature with Consul.

I hope this helps you.