From 8f5ab8aa7a0b9b09839268d42ae8590d7329b74b Mon Sep 17 00:00:00 2001 From: leonluc-dev Date: Mon, 22 May 2023 12:35:10 +0200 Subject: [PATCH 01/27] Update servicediscovery documentation to include custom provider --- docs/features/servicediscovery.rst | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/docs/features/servicediscovery.rst b/docs/features/servicediscovery.rst index 94b993cdf..253aaffae 100644 --- a/docs/features/servicediscovery.rst +++ b/docs/features/servicediscovery.rst @@ -242,3 +242,50 @@ Ocelot also allows you to set DynamicRoutes which lets you set rate limiting rul This configuration means that if you have a request come into Ocelot on /product/* then dynamic routing will kick in and ocelot will use the rate limiting set against the product service in the DynamicRoutes section. Please take a look through all of the docs to understand these options. + +Custom +^^^^^^ + +Ocelot also allows you to create a custom ServiceDiscovery implementation. +This is done by implementing the IServiceDiscoveryProvider interface like in the following example: + +.. code-block:: csharp + + public class MyServiceDiscoveryProvider : IServiceDiscoveryProvider + { + private readonly DownstreamRoute _downstreamRoute; + + public MyServiceDiscoveryProvider(DownstreamRoute downstreamRoute) + { + _downstreamRoute = downstreamRoute; + } + + public async Task> Get() + { + var services = new List(); + //... + //Add service(s) to the list matching the _downstreamRoute + return services; + } + } + +And set its class name as the provider type in ocelot.json: + +.. code-block:: json + + "GlobalConfiguration": { + "ServiceDiscoveryProvider": { + "Type": "MyServiceDiscoveryProvider" + } + } + +Finally, in Startup.cs register a ServiceDiscoveryFinderDelegate to initialize and return the provider: + +.. code-block:: csharp + + ServiceDiscoveryFinderDelegate serviceDiscoveryFinder = (provider, config, route) => + { + return new MyServiceDiscoveryProvider(route); + }; + services.AddOcelot().Services.AddSingleton(serviceDiscoveryFinder); + From 2467d5a1865c298909e6b0dd4d9e6f89ba5557a8 Mon Sep 17 00:00:00 2001 From: raman-m Date: Wed, 24 May 2023 12:49:26 +0300 Subject: [PATCH 02/27] Update servicediscovery.rst Custom Providers paragraph --- docs/features/servicediscovery.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/features/servicediscovery.rst b/docs/features/servicediscovery.rst index 253aaffae..a0d61243c 100644 --- a/docs/features/servicediscovery.rst +++ b/docs/features/servicediscovery.rst @@ -243,11 +243,11 @@ This configuration means that if you have a request come into Ocelot on /product Please take a look through all of the docs to understand these options. -Custom -^^^^^^ +Custom providers +^^^^^^^^^^^^^^^^ Ocelot also allows you to create a custom ServiceDiscovery implementation. -This is done by implementing the IServiceDiscoveryProvider interface like in the following example: +This is done by implementing the ``IServiceDiscoveryProvider`` interface like in the following example: .. code-block:: csharp @@ -269,7 +269,7 @@ This is done by implementing the IServiceDiscoveryProvider interface like in the } } -And set its class name as the provider type in ocelot.json: +And set its class name as the provider type in **ocelot.json**: .. code-block:: json @@ -279,7 +279,7 @@ And set its class name as the provider type in ocelot.json: } } -Finally, in Startup.cs register a ServiceDiscoveryFinderDelegate to initialize and return the provider: +Finally, in **Startup.cs** register a ``ServiceDiscoveryFinderDelegate`` to initialize and return the provider: .. code-block:: csharp From 182d9accb4ccea13b4ac1d6483da031eca0e4083 Mon Sep 17 00:00:00 2001 From: raman-m Date: Wed, 24 May 2023 12:55:04 +0300 Subject: [PATCH 03/27] Update servicediscovery.rst Fix lower/upper case in paragraph name --- docs/features/servicediscovery.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/servicediscovery.rst b/docs/features/servicediscovery.rst index a0d61243c..3a0e728aa 100644 --- a/docs/features/servicediscovery.rst +++ b/docs/features/servicediscovery.rst @@ -243,7 +243,7 @@ This configuration means that if you have a request come into Ocelot on /product Please take a look through all of the docs to understand these options. -Custom providers +Custom Providers ^^^^^^^^^^^^^^^^ Ocelot also allows you to create a custom ServiceDiscovery implementation. From 9e0710434c15910888ec707a5c9e9c52d130f011 Mon Sep 17 00:00:00 2001 From: leonluc-dev Date: Thu, 25 May 2023 13:43:34 +0200 Subject: [PATCH 04/27] Added custom service provider sample --- .../OcelotCustom/ApiGateway/ApiGateway.csproj | 24 ++++++++++ samples/OcelotCustom/ApiGateway/Program.cs | 48 +++++++++++++++++++ .../ApiGateway/Properties/launchSettings.json | 27 +++++++++++ .../MyServiceDiscoveryProvider.cs | 45 +++++++++++++++++ .../OcelotCustom/ApiGateway/appsettings.json | 19 ++++++++ samples/OcelotCustom/ApiGateway/ocelot.json | 19 ++++++++ .../Controllers/CategoryController.cs | 17 +++++++ .../DownstreamService.csproj | 11 +++++ .../OcelotCustom/DownstreamService/Program.cs | 21 ++++++++ .../Properties/launchSettings.json | 29 +++++++++++ .../OcelotCustom/DownstreamService/Startup.cs | 40 ++++++++++++++++ .../appsettings.Development.json | 10 ++++ .../DownstreamService/appsettings.json | 16 +++++++ samples/OcelotCustom/OcelotCustom.sln | 31 ++++++++++++ samples/OcelotCustom/README.md | 29 +++++++++++ 15 files changed, 386 insertions(+) create mode 100644 samples/OcelotCustom/ApiGateway/ApiGateway.csproj create mode 100644 samples/OcelotCustom/ApiGateway/Program.cs create mode 100644 samples/OcelotCustom/ApiGateway/Properties/launchSettings.json create mode 100644 samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs create mode 100644 samples/OcelotCustom/ApiGateway/appsettings.json create mode 100644 samples/OcelotCustom/ApiGateway/ocelot.json create mode 100644 samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs create mode 100644 samples/OcelotCustom/DownstreamService/DownstreamService.csproj create mode 100644 samples/OcelotCustom/DownstreamService/Program.cs create mode 100644 samples/OcelotCustom/DownstreamService/Properties/launchSettings.json create mode 100644 samples/OcelotCustom/DownstreamService/Startup.cs create mode 100644 samples/OcelotCustom/DownstreamService/appsettings.Development.json create mode 100644 samples/OcelotCustom/DownstreamService/appsettings.json create mode 100644 samples/OcelotCustom/OcelotCustom.sln create mode 100644 samples/OcelotCustom/README.md diff --git a/samples/OcelotCustom/ApiGateway/ApiGateway.csproj b/samples/OcelotCustom/ApiGateway/ApiGateway.csproj new file mode 100644 index 000000000..2d7238d54 --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/ApiGateway.csproj @@ -0,0 +1,24 @@ + + + + net7.0 + + + + + + + + + + + + PreserveNewest + + + + + + + + diff --git a/samples/OcelotCustom/ApiGateway/Program.cs b/samples/OcelotCustom/ApiGateway/Program.cs new file mode 100644 index 000000000..7977eb031 --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/Program.cs @@ -0,0 +1,48 @@ +namespace ApiGateway +{ + using ApiGateway.ServiceDiscovery; + using Microsoft.AspNetCore; + using Microsoft.AspNetCore.Hosting; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Ocelot.DependencyInjection; + using Ocelot.Middleware; + using Ocelot.ServiceDiscovery; + using System; + + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseUrls("http://localhost:5000") + .ConfigureAppConfiguration((hostingContext, config) => + { + config + .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) + .AddJsonFile("appsettings.json", true, true) + .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true) + .AddJsonFile("ocelot.json", false, false) + .AddEnvironmentVariables(); + }) + .ConfigureServices(s => + { + ServiceDiscoveryFinderDelegate serviceDiscoveryFinder = (serviceProvider, config, downstreamRoute) => + { + return new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute); + }; + + s.AddSingleton(serviceDiscoveryFinder); + s.AddOcelot(); + }) + .Configure(a => + { + a.UseOcelot().Wait(); + }) + .Build(); + } +} diff --git a/samples/OcelotCustom/ApiGateway/Properties/launchSettings.json b/samples/OcelotCustom/ApiGateway/Properties/launchSettings.json new file mode 100644 index 000000000..c1b4df874 --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:54060/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "ApiGateway": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:54061/" + } + } +} diff --git a/samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs b/samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs new file mode 100644 index 000000000..5f6e02411 --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs @@ -0,0 +1,45 @@ +using Ocelot.Configuration; +using Ocelot.ServiceDiscovery.Providers; +using Ocelot.Values; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ApiGateway.ServiceDiscovery +{ + public class MyServiceDiscoveryProvider : IServiceDiscoveryProvider + { + private readonly IServiceProvider _serviceProvider; + private readonly ServiceProviderConfiguration _config; + private readonly DownstreamRoute _downstreamRoute; + + public MyServiceDiscoveryProvider(IServiceProvider serviceProvider, ServiceProviderConfiguration config, DownstreamRoute downstreamRoute) + { + _serviceProvider = serviceProvider; + _config = config; + _downstreamRoute = downstreamRoute; + } + + public Task> Get() + { + //Returns a list of service(s) that match the downstream route passed to the provider + var services = new List(); + + if(_downstreamRoute.ServiceName.Equals("downstream-service")) + { + //For this example we simply do a manual match to a single service + var service = new Service( + name: "downstream-service", + hostAndPort: new ServiceHostAndPort("localhost", 5001), + id: "downstream-service-1", + version: "1.0", + tags: new string[] { "downstream", "hardcoded" } + ); + + services.Add(service); + } + + return Task.FromResult(services); + } + } +} diff --git a/samples/OcelotCustom/ApiGateway/appsettings.json b/samples/OcelotCustom/ApiGateway/appsettings.json new file mode 100644 index 000000000..454577ddb --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/appsettings.json @@ -0,0 +1,19 @@ +{ + "Logging": { + "IncludeScopes": true, + "LogLevel": { + "Default": "Trace", + "System": "Information", + "Microsoft": "Information" + } + }, + "spring": { + "application": { "name": "Ocelot-Gateway" }, + "cloud": { + "config": { + "uri": "http://localhost:5000", + "validateCertificates": false + } + } + } +} diff --git a/samples/OcelotCustom/ApiGateway/ocelot.json b/samples/OcelotCustom/ApiGateway/ocelot.json new file mode 100644 index 000000000..0b288280e --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/ocelot.json @@ -0,0 +1,19 @@ +{ + "Routes": [ + { + "DownstreamPathTemplate": "/api/Category", + "DownstreamScheme": "http", + "UpstreamPathTemplate": "/Category", + "ServiceName": "downstream-service", + "UpstreamHttpMethod": [ "Get" ], + "FileCacheOptions": { "TtlSeconds": 15 } + } + ], + "GlobalConfiguration": { + "RequestIdKey": "OcRequestId", + "AdministrationPath": "/administration", + "ServiceDiscoveryProvider": { + "Type": "MyServiceDiscoveryProvider" + } + } +} diff --git a/samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs b/samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs new file mode 100644 index 000000000..5ce38f475 --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +using Microsoft.AspNetCore.Mvc; + +namespace DownstreamService.Controllers +{ + [Route("api/[controller]")] + public class CategoryController : Controller + { + // GET api/values + [HttpGet] + public IEnumerable Get() + { + return new[] { "category1", "category2" }; + } + } +} diff --git a/samples/OcelotCustom/DownstreamService/DownstreamService.csproj b/samples/OcelotCustom/DownstreamService/DownstreamService.csproj new file mode 100644 index 000000000..a4104fc03 --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/DownstreamService.csproj @@ -0,0 +1,11 @@ + + + + net7.0 + + + + + + + diff --git a/samples/OcelotCustom/DownstreamService/Program.cs b/samples/OcelotCustom/DownstreamService/Program.cs new file mode 100644 index 000000000..130b46f0e --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/Program.cs @@ -0,0 +1,21 @@ +using System; + +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; + +namespace DownstreamService +{ + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseUrls($"http://{Environment.MachineName}:5001") + .UseStartup() + .Build(); + } +} diff --git a/samples/OcelotCustom/DownstreamService/Properties/launchSettings.json b/samples/OcelotCustom/DownstreamService/Properties/launchSettings.json new file mode 100644 index 000000000..0c084db8e --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:53908/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "DownstreamService": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:53909/" + } + } +} diff --git a/samples/OcelotCustom/DownstreamService/Startup.cs b/samples/OcelotCustom/DownstreamService/Startup.cs new file mode 100644 index 000000000..af07bc2eb --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/Startup.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace DownstreamService +{ + using Microsoft.Extensions.Hosting; + + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + app.UseEndpoints(configure => + { + configure.MapControllers(); + }); + } + } +} diff --git a/samples/OcelotCustom/DownstreamService/appsettings.Development.json b/samples/OcelotCustom/DownstreamService/appsettings.Development.json new file mode 100644 index 000000000..fa8ce71a9 --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/samples/OcelotCustom/DownstreamService/appsettings.json b/samples/OcelotCustom/DownstreamService/appsettings.json new file mode 100644 index 000000000..255a1bbcd --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/appsettings.json @@ -0,0 +1,16 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { "Default": "Warning" } + }, + "spring": { + "application": { "name": "downstream-service" }, + "cloud": { + "config": { + "uri": "http://localhost:5001", + "validate_certificates": false + } + } + } +} + diff --git a/samples/OcelotCustom/OcelotCustom.sln b/samples/OcelotCustom/OcelotCustom.sln new file mode 100644 index 000000000..62eb6ebc4 --- /dev/null +++ b/samples/OcelotCustom/OcelotCustom.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DownstreamService", "./DownstreamService/DownstreamService.csproj", "{2982C147-9446-47FE-862E-E689B64CC7E7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiGateway", "./ApiGateway/ApiGateway.csproj", "{006CF27E-5400-43E9-B511-C54EC1B9C546}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2982C147-9446-47FE-862E-E689B64CC7E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2982C147-9446-47FE-862E-E689B64CC7E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2982C147-9446-47FE-862E-E689B64CC7E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2982C147-9446-47FE-862E-E689B64CC7E7}.Release|Any CPU.Build.0 = Release|Any CPU + {006CF27E-5400-43E9-B511-C54EC1B9C546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {006CF27E-5400-43E9-B511-C54EC1B9C546}.Debug|Any CPU.Build.0 = Debug|Any CPU + {006CF27E-5400-43E9-B511-C54EC1B9C546}.Release|Any CPU.ActiveCfg = Release|Any CPU + {006CF27E-5400-43E9-B511-C54EC1B9C546}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2C604707-2EA1-4CCF-A89C-22B613052C8D} + EndGlobalSection +EndGlobal diff --git a/samples/OcelotCustom/README.md b/samples/OcelotCustom/README.md new file mode 100644 index 000000000..ec0fcecb6 --- /dev/null +++ b/samples/OcelotCustom/README.md @@ -0,0 +1,29 @@ +#Example how to use custom service discovery + +This sample constains a simple setup using a custom service discovery provider. + +##Instructions + +1. Get Downstream service running + + ``` + cd ./DownstreamService/ + dotnet run + ``` + + Leave the service running + +2. Get API Gateway running + + ``` + cd ./ApiGateway/ + dotnet run + ``` + + Leave the service running + +3. Make a http request to http://localhost:5000/Category you should get the following response + + ```json + ["category1","category2"] + ``` \ No newline at end of file From a0d865a986ded9cb2ce0037b6e052f1a6a78df8c Mon Sep 17 00:00:00 2001 From: leonluc-dev Date: Thu, 25 May 2023 13:45:37 +0200 Subject: [PATCH 05/27] Minor clarification to custom service discovery provider docs --- docs/features/servicediscovery.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/features/servicediscovery.rst b/docs/features/servicediscovery.rst index 3a0e728aa..d52763fa4 100644 --- a/docs/features/servicediscovery.rst +++ b/docs/features/servicediscovery.rst @@ -279,7 +279,7 @@ And set its class name as the provider type in **ocelot.json**: } } -Finally, in **Startup.cs** register a ``ServiceDiscoveryFinderDelegate`` to initialize and return the provider: +Finally, in the application's **ConfigureServices** method register a ``ServiceDiscoveryFinderDelegate`` to initialize and return the provider: .. code-block:: csharp @@ -287,5 +287,6 @@ Finally, in **Startup.cs** register a ``ServiceDiscoveryFinderDelegate`` to init { return new MyServiceDiscoveryProvider(route); }; - services.AddOcelot().Services.AddSingleton(serviceDiscoveryFinder); + services.AddSingleton(serviceDiscoveryFinder); + services.AddOcelot(); From b4bf163a41c8f0c59b094902018e85f7021063b7 Mon Sep 17 00:00:00 2001 From: raman-m Date: Fri, 26 May 2023 15:29:18 +0300 Subject: [PATCH 06/27] Move usings to the top. Use file-scoped namespace declaration --- samples/OcelotCustom/ApiGateway/Program.cs | 85 +++++++++++----------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/samples/OcelotCustom/ApiGateway/Program.cs b/samples/OcelotCustom/ApiGateway/Program.cs index 7977eb031..24e6c1e56 100644 --- a/samples/OcelotCustom/ApiGateway/Program.cs +++ b/samples/OcelotCustom/ApiGateway/Program.cs @@ -1,48 +1,49 @@ -namespace ApiGateway -{ - using ApiGateway.ServiceDiscovery; - using Microsoft.AspNetCore; - using Microsoft.AspNetCore.Hosting; - using Microsoft.Extensions.Configuration; - using Microsoft.Extensions.DependencyInjection; - using Ocelot.DependencyInjection; - using Ocelot.Middleware; - using Ocelot.ServiceDiscovery; - using System; +using ApiGateway.ServiceDiscovery; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +using Ocelot.DependencyInjection; +using Ocelot.Middleware; +using Ocelot.ServiceDiscovery; + +using System; - public class Program +namespace ApiGateway; + +public class Program +{ + public static void Main(string[] args) { - public static void Main(string[] args) - { - BuildWebHost(args).Run(); - } + BuildWebHost(args).Run(); + } - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseUrls("http://localhost:5000") - .ConfigureAppConfiguration((hostingContext, config) => - { - config - .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) - .AddJsonFile("appsettings.json", true, true) - .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true) - .AddJsonFile("ocelot.json", false, false) - .AddEnvironmentVariables(); - }) - .ConfigureServices(s => + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseUrls("http://localhost:5000") + .ConfigureAppConfiguration((hostingContext, config) => + { + config + .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) + .AddJsonFile("appsettings.json", true, true) + .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true) + .AddJsonFile("ocelot.json", false, false) + .AddEnvironmentVariables(); + }) + .ConfigureServices(s => + { + ServiceDiscoveryFinderDelegate serviceDiscoveryFinder = (serviceProvider, config, downstreamRoute) => { - ServiceDiscoveryFinderDelegate serviceDiscoveryFinder = (serviceProvider, config, downstreamRoute) => - { - return new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute); - }; + return new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute); + }; - s.AddSingleton(serviceDiscoveryFinder); - s.AddOcelot(); - }) - .Configure(a => - { - a.UseOcelot().Wait(); - }) - .Build(); - } + s.AddSingleton(serviceDiscoveryFinder); + s.AddOcelot(); + }) + .Configure(a => + { + a.UseOcelot().Wait(); + }) + .Build(); } From c4d2f08bf486fea7f32f74c5b557e99b3c0ff5d7 Mon Sep 17 00:00:00 2001 From: leonluc-dev Date: Wed, 31 May 2023 14:03:00 +0200 Subject: [PATCH 07/27] Moved custom service discovery sample Added sample to Ocelot.sln --- Ocelot.sln | 17 +++++++++++++++++ .../ApiGateway/ApiGateway.csproj | 0 .../ApiGateway/Program.cs | 0 .../ApiGateway/Properties/launchSettings.json | 0 .../MyServiceDiscoveryProvider.cs | 0 .../ApiGateway/appsettings.json | 0 .../ApiGateway/ocelot.json | 0 .../Controllers/CategoryController.cs | 0 .../DownstreamService/DownstreamService.csproj | 0 .../DownstreamService/Program.cs | 0 .../Properties/launchSettings.json | 0 .../DownstreamService/Startup.cs | 0 .../appsettings.Development.json | 0 .../DownstreamService/appsettings.json | 0 .../OcelotServiceDiscovery.sln} | 8 ++++---- .../README.md | 0 16 files changed, 21 insertions(+), 4 deletions(-) rename samples/{OcelotCustom => OcelotServiceDiscovery}/ApiGateway/ApiGateway.csproj (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/ApiGateway/Program.cs (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/ApiGateway/Properties/launchSettings.json (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/ApiGateway/appsettings.json (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/ApiGateway/ocelot.json (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/DownstreamService/Controllers/CategoryController.cs (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/DownstreamService/DownstreamService.csproj (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/DownstreamService/Program.cs (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/DownstreamService/Properties/launchSettings.json (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/DownstreamService/Startup.cs (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/DownstreamService/appsettings.Development.json (100%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/DownstreamService/appsettings.json (100%) rename samples/{OcelotCustom/OcelotCustom.sln => OcelotServiceDiscovery/OcelotServiceDiscovery.sln} (88%) rename samples/{OcelotCustom => OcelotServiceDiscovery}/README.md (100%) diff --git a/Ocelot.sln b/Ocelot.sln index b59c188a2..e13fc798a 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -86,6 +86,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "open-tracing", "open-tracin EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OcelotOpenTracing", "samples\OcelotOpenTracing\OcelotOpenTracing.csproj", "{C9427E78-4281-4F59-A66E-17C0B66550E5}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "service-discovery", "service-discovery", "{25C30AAA-12DD-4BA5-A53F-9271E54EBAB7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiGateway", "samples\OcelotServiceDiscovery\ApiGateway\ApiGateway.csproj", "{D37209EA-C13E-42AE-B851-A8604F1FCD0E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DownstreamService", "samples\OcelotServiceDiscovery\DownstreamService\DownstreamService.csproj", "{E2AC741A-4120-4D59-B5E4-16382ED45E8D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -188,6 +194,14 @@ Global {C9427E78-4281-4F59-A66E-17C0B66550E5}.Debug|Any CPU.Build.0 = Debug|Any CPU {C9427E78-4281-4F59-A66E-17C0B66550E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {C9427E78-4281-4F59-A66E-17C0B66550E5}.Release|Any CPU.Build.0 = Release|Any CPU + {D37209EA-C13E-42AE-B851-A8604F1FCD0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D37209EA-C13E-42AE-B851-A8604F1FCD0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D37209EA-C13E-42AE-B851-A8604F1FCD0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D37209EA-C13E-42AE-B851-A8604F1FCD0E}.Release|Any CPU.Build.0 = Release|Any CPU + {E2AC741A-4120-4D59-B5E4-16382ED45E8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2AC741A-4120-4D59-B5E4-16382ED45E8D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2AC741A-4120-4D59-B5E4-16382ED45E8D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2AC741A-4120-4D59-B5E4-16382ED45E8D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -224,6 +238,9 @@ Global {11C622AD-8C0A-4CF4-811B-3DBB76550797} = {5CFB79B7-C9DC-45A4-9A75-625D92471702} {731C6A8A-69ED-445C-A132-C638AA93F9C7} = {8FA0CBA0-0338-48EB-B37F-83CA5022237C} {C9427E78-4281-4F59-A66E-17C0B66550E5} = {731C6A8A-69ED-445C-A132-C638AA93F9C7} + {25C30AAA-12DD-4BA5-A53F-9271E54EBAB7} = {8FA0CBA0-0338-48EB-B37F-83CA5022237C} + {D37209EA-C13E-42AE-B851-A8604F1FCD0E} = {25C30AAA-12DD-4BA5-A53F-9271E54EBAB7} + {E2AC741A-4120-4D59-B5E4-16382ED45E8D} = {25C30AAA-12DD-4BA5-A53F-9271E54EBAB7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {21476EFF-778A-4F97-8A56-D1AF1CEC0C48} diff --git a/samples/OcelotCustom/ApiGateway/ApiGateway.csproj b/samples/OcelotServiceDiscovery/ApiGateway/ApiGateway.csproj similarity index 100% rename from samples/OcelotCustom/ApiGateway/ApiGateway.csproj rename to samples/OcelotServiceDiscovery/ApiGateway/ApiGateway.csproj diff --git a/samples/OcelotCustom/ApiGateway/Program.cs b/samples/OcelotServiceDiscovery/ApiGateway/Program.cs similarity index 100% rename from samples/OcelotCustom/ApiGateway/Program.cs rename to samples/OcelotServiceDiscovery/ApiGateway/Program.cs diff --git a/samples/OcelotCustom/ApiGateway/Properties/launchSettings.json b/samples/OcelotServiceDiscovery/ApiGateway/Properties/launchSettings.json similarity index 100% rename from samples/OcelotCustom/ApiGateway/Properties/launchSettings.json rename to samples/OcelotServiceDiscovery/ApiGateway/Properties/launchSettings.json diff --git a/samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs b/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs similarity index 100% rename from samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs rename to samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs diff --git a/samples/OcelotCustom/ApiGateway/appsettings.json b/samples/OcelotServiceDiscovery/ApiGateway/appsettings.json similarity index 100% rename from samples/OcelotCustom/ApiGateway/appsettings.json rename to samples/OcelotServiceDiscovery/ApiGateway/appsettings.json diff --git a/samples/OcelotCustom/ApiGateway/ocelot.json b/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json similarity index 100% rename from samples/OcelotCustom/ApiGateway/ocelot.json rename to samples/OcelotServiceDiscovery/ApiGateway/ocelot.json diff --git a/samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs similarity index 100% rename from samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs rename to samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs diff --git a/samples/OcelotCustom/DownstreamService/DownstreamService.csproj b/samples/OcelotServiceDiscovery/DownstreamService/DownstreamService.csproj similarity index 100% rename from samples/OcelotCustom/DownstreamService/DownstreamService.csproj rename to samples/OcelotServiceDiscovery/DownstreamService/DownstreamService.csproj diff --git a/samples/OcelotCustom/DownstreamService/Program.cs b/samples/OcelotServiceDiscovery/DownstreamService/Program.cs similarity index 100% rename from samples/OcelotCustom/DownstreamService/Program.cs rename to samples/OcelotServiceDiscovery/DownstreamService/Program.cs diff --git a/samples/OcelotCustom/DownstreamService/Properties/launchSettings.json b/samples/OcelotServiceDiscovery/DownstreamService/Properties/launchSettings.json similarity index 100% rename from samples/OcelotCustom/DownstreamService/Properties/launchSettings.json rename to samples/OcelotServiceDiscovery/DownstreamService/Properties/launchSettings.json diff --git a/samples/OcelotCustom/DownstreamService/Startup.cs b/samples/OcelotServiceDiscovery/DownstreamService/Startup.cs similarity index 100% rename from samples/OcelotCustom/DownstreamService/Startup.cs rename to samples/OcelotServiceDiscovery/DownstreamService/Startup.cs diff --git a/samples/OcelotCustom/DownstreamService/appsettings.Development.json b/samples/OcelotServiceDiscovery/DownstreamService/appsettings.Development.json similarity index 100% rename from samples/OcelotCustom/DownstreamService/appsettings.Development.json rename to samples/OcelotServiceDiscovery/DownstreamService/appsettings.Development.json diff --git a/samples/OcelotCustom/DownstreamService/appsettings.json b/samples/OcelotServiceDiscovery/DownstreamService/appsettings.json similarity index 100% rename from samples/OcelotCustom/DownstreamService/appsettings.json rename to samples/OcelotServiceDiscovery/DownstreamService/appsettings.json diff --git a/samples/OcelotCustom/OcelotCustom.sln b/samples/OcelotServiceDiscovery/OcelotServiceDiscovery.sln similarity index 88% rename from samples/OcelotCustom/OcelotCustom.sln rename to samples/OcelotServiceDiscovery/OcelotServiceDiscovery.sln index 62eb6ebc4..78a246b63 100644 --- a/samples/OcelotCustom/OcelotCustom.sln +++ b/samples/OcelotServiceDiscovery/OcelotServiceDiscovery.sln @@ -1,11 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27428.2027 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33122.133 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DownstreamService", "./DownstreamService/DownstreamService.csproj", "{2982C147-9446-47FE-862E-E689B64CC7E7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DownstreamService", "./DownstreamService/DownstreamService.csproj", "{2982C147-9446-47FE-862E-E689B64CC7E7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiGateway", "./ApiGateway/ApiGateway.csproj", "{006CF27E-5400-43E9-B511-C54EC1B9C546}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiGateway", "./ApiGateway/ApiGateway.csproj", "{006CF27E-5400-43E9-B511-C54EC1B9C546}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/samples/OcelotCustom/README.md b/samples/OcelotServiceDiscovery/README.md similarity index 100% rename from samples/OcelotCustom/README.md rename to samples/OcelotServiceDiscovery/README.md From 5d1c4797ed84f4b97a2e091c8e5f2c8a664d9dc9 Mon Sep 17 00:00:00 2001 From: leonluc-dev Date: Thu, 25 May 2023 13:43:34 +0200 Subject: [PATCH 08/27] Added custom service provider sample --- .../OcelotCustom/ApiGateway/ApiGateway.csproj | 24 ++++++++++ samples/OcelotCustom/ApiGateway/Program.cs | 48 +++++++++++++++++++ .../ApiGateway/Properties/launchSettings.json | 27 +++++++++++ .../MyServiceDiscoveryProvider.cs | 45 +++++++++++++++++ .../OcelotCustom/ApiGateway/appsettings.json | 19 ++++++++ samples/OcelotCustom/ApiGateway/ocelot.json | 19 ++++++++ .../Controllers/CategoryController.cs | 17 +++++++ .../DownstreamService.csproj | 11 +++++ .../OcelotCustom/DownstreamService/Program.cs | 21 ++++++++ .../Properties/launchSettings.json | 29 +++++++++++ .../OcelotCustom/DownstreamService/Startup.cs | 40 ++++++++++++++++ .../appsettings.Development.json | 10 ++++ .../DownstreamService/appsettings.json | 16 +++++++ samples/OcelotCustom/OcelotCustom.sln | 31 ++++++++++++ samples/OcelotCustom/README.md | 29 +++++++++++ 15 files changed, 386 insertions(+) create mode 100644 samples/OcelotCustom/ApiGateway/ApiGateway.csproj create mode 100644 samples/OcelotCustom/ApiGateway/Program.cs create mode 100644 samples/OcelotCustom/ApiGateway/Properties/launchSettings.json create mode 100644 samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs create mode 100644 samples/OcelotCustom/ApiGateway/appsettings.json create mode 100644 samples/OcelotCustom/ApiGateway/ocelot.json create mode 100644 samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs create mode 100644 samples/OcelotCustom/DownstreamService/DownstreamService.csproj create mode 100644 samples/OcelotCustom/DownstreamService/Program.cs create mode 100644 samples/OcelotCustom/DownstreamService/Properties/launchSettings.json create mode 100644 samples/OcelotCustom/DownstreamService/Startup.cs create mode 100644 samples/OcelotCustom/DownstreamService/appsettings.Development.json create mode 100644 samples/OcelotCustom/DownstreamService/appsettings.json create mode 100644 samples/OcelotCustom/OcelotCustom.sln create mode 100644 samples/OcelotCustom/README.md diff --git a/samples/OcelotCustom/ApiGateway/ApiGateway.csproj b/samples/OcelotCustom/ApiGateway/ApiGateway.csproj new file mode 100644 index 000000000..2d7238d54 --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/ApiGateway.csproj @@ -0,0 +1,24 @@ + + + + net7.0 + + + + + + + + + + + + PreserveNewest + + + + + + + + diff --git a/samples/OcelotCustom/ApiGateway/Program.cs b/samples/OcelotCustom/ApiGateway/Program.cs new file mode 100644 index 000000000..7977eb031 --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/Program.cs @@ -0,0 +1,48 @@ +namespace ApiGateway +{ + using ApiGateway.ServiceDiscovery; + using Microsoft.AspNetCore; + using Microsoft.AspNetCore.Hosting; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Ocelot.DependencyInjection; + using Ocelot.Middleware; + using Ocelot.ServiceDiscovery; + using System; + + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseUrls("http://localhost:5000") + .ConfigureAppConfiguration((hostingContext, config) => + { + config + .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) + .AddJsonFile("appsettings.json", true, true) + .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true) + .AddJsonFile("ocelot.json", false, false) + .AddEnvironmentVariables(); + }) + .ConfigureServices(s => + { + ServiceDiscoveryFinderDelegate serviceDiscoveryFinder = (serviceProvider, config, downstreamRoute) => + { + return new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute); + }; + + s.AddSingleton(serviceDiscoveryFinder); + s.AddOcelot(); + }) + .Configure(a => + { + a.UseOcelot().Wait(); + }) + .Build(); + } +} diff --git a/samples/OcelotCustom/ApiGateway/Properties/launchSettings.json b/samples/OcelotCustom/ApiGateway/Properties/launchSettings.json new file mode 100644 index 000000000..c1b4df874 --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:54060/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "ApiGateway": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:54061/" + } + } +} diff --git a/samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs b/samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs new file mode 100644 index 000000000..5f6e02411 --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs @@ -0,0 +1,45 @@ +using Ocelot.Configuration; +using Ocelot.ServiceDiscovery.Providers; +using Ocelot.Values; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ApiGateway.ServiceDiscovery +{ + public class MyServiceDiscoveryProvider : IServiceDiscoveryProvider + { + private readonly IServiceProvider _serviceProvider; + private readonly ServiceProviderConfiguration _config; + private readonly DownstreamRoute _downstreamRoute; + + public MyServiceDiscoveryProvider(IServiceProvider serviceProvider, ServiceProviderConfiguration config, DownstreamRoute downstreamRoute) + { + _serviceProvider = serviceProvider; + _config = config; + _downstreamRoute = downstreamRoute; + } + + public Task> Get() + { + //Returns a list of service(s) that match the downstream route passed to the provider + var services = new List(); + + if(_downstreamRoute.ServiceName.Equals("downstream-service")) + { + //For this example we simply do a manual match to a single service + var service = new Service( + name: "downstream-service", + hostAndPort: new ServiceHostAndPort("localhost", 5001), + id: "downstream-service-1", + version: "1.0", + tags: new string[] { "downstream", "hardcoded" } + ); + + services.Add(service); + } + + return Task.FromResult(services); + } + } +} diff --git a/samples/OcelotCustom/ApiGateway/appsettings.json b/samples/OcelotCustom/ApiGateway/appsettings.json new file mode 100644 index 000000000..454577ddb --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/appsettings.json @@ -0,0 +1,19 @@ +{ + "Logging": { + "IncludeScopes": true, + "LogLevel": { + "Default": "Trace", + "System": "Information", + "Microsoft": "Information" + } + }, + "spring": { + "application": { "name": "Ocelot-Gateway" }, + "cloud": { + "config": { + "uri": "http://localhost:5000", + "validateCertificates": false + } + } + } +} diff --git a/samples/OcelotCustom/ApiGateway/ocelot.json b/samples/OcelotCustom/ApiGateway/ocelot.json new file mode 100644 index 000000000..0b288280e --- /dev/null +++ b/samples/OcelotCustom/ApiGateway/ocelot.json @@ -0,0 +1,19 @@ +{ + "Routes": [ + { + "DownstreamPathTemplate": "/api/Category", + "DownstreamScheme": "http", + "UpstreamPathTemplate": "/Category", + "ServiceName": "downstream-service", + "UpstreamHttpMethod": [ "Get" ], + "FileCacheOptions": { "TtlSeconds": 15 } + } + ], + "GlobalConfiguration": { + "RequestIdKey": "OcRequestId", + "AdministrationPath": "/administration", + "ServiceDiscoveryProvider": { + "Type": "MyServiceDiscoveryProvider" + } + } +} diff --git a/samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs b/samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs new file mode 100644 index 000000000..5ce38f475 --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +using Microsoft.AspNetCore.Mvc; + +namespace DownstreamService.Controllers +{ + [Route("api/[controller]")] + public class CategoryController : Controller + { + // GET api/values + [HttpGet] + public IEnumerable Get() + { + return new[] { "category1", "category2" }; + } + } +} diff --git a/samples/OcelotCustom/DownstreamService/DownstreamService.csproj b/samples/OcelotCustom/DownstreamService/DownstreamService.csproj new file mode 100644 index 000000000..a4104fc03 --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/DownstreamService.csproj @@ -0,0 +1,11 @@ + + + + net7.0 + + + + + + + diff --git a/samples/OcelotCustom/DownstreamService/Program.cs b/samples/OcelotCustom/DownstreamService/Program.cs new file mode 100644 index 000000000..130b46f0e --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/Program.cs @@ -0,0 +1,21 @@ +using System; + +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; + +namespace DownstreamService +{ + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseUrls($"http://{Environment.MachineName}:5001") + .UseStartup() + .Build(); + } +} diff --git a/samples/OcelotCustom/DownstreamService/Properties/launchSettings.json b/samples/OcelotCustom/DownstreamService/Properties/launchSettings.json new file mode 100644 index 000000000..0c084db8e --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:53908/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "DownstreamService": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:53909/" + } + } +} diff --git a/samples/OcelotCustom/DownstreamService/Startup.cs b/samples/OcelotCustom/DownstreamService/Startup.cs new file mode 100644 index 000000000..af07bc2eb --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/Startup.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace DownstreamService +{ + using Microsoft.Extensions.Hosting; + + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + app.UseEndpoints(configure => + { + configure.MapControllers(); + }); + } + } +} diff --git a/samples/OcelotCustom/DownstreamService/appsettings.Development.json b/samples/OcelotCustom/DownstreamService/appsettings.Development.json new file mode 100644 index 000000000..fa8ce71a9 --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/samples/OcelotCustom/DownstreamService/appsettings.json b/samples/OcelotCustom/DownstreamService/appsettings.json new file mode 100644 index 000000000..255a1bbcd --- /dev/null +++ b/samples/OcelotCustom/DownstreamService/appsettings.json @@ -0,0 +1,16 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { "Default": "Warning" } + }, + "spring": { + "application": { "name": "downstream-service" }, + "cloud": { + "config": { + "uri": "http://localhost:5001", + "validate_certificates": false + } + } + } +} + diff --git a/samples/OcelotCustom/OcelotCustom.sln b/samples/OcelotCustom/OcelotCustom.sln new file mode 100644 index 000000000..62eb6ebc4 --- /dev/null +++ b/samples/OcelotCustom/OcelotCustom.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DownstreamService", "./DownstreamService/DownstreamService.csproj", "{2982C147-9446-47FE-862E-E689B64CC7E7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiGateway", "./ApiGateway/ApiGateway.csproj", "{006CF27E-5400-43E9-B511-C54EC1B9C546}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2982C147-9446-47FE-862E-E689B64CC7E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2982C147-9446-47FE-862E-E689B64CC7E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2982C147-9446-47FE-862E-E689B64CC7E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2982C147-9446-47FE-862E-E689B64CC7E7}.Release|Any CPU.Build.0 = Release|Any CPU + {006CF27E-5400-43E9-B511-C54EC1B9C546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {006CF27E-5400-43E9-B511-C54EC1B9C546}.Debug|Any CPU.Build.0 = Debug|Any CPU + {006CF27E-5400-43E9-B511-C54EC1B9C546}.Release|Any CPU.ActiveCfg = Release|Any CPU + {006CF27E-5400-43E9-B511-C54EC1B9C546}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2C604707-2EA1-4CCF-A89C-22B613052C8D} + EndGlobalSection +EndGlobal diff --git a/samples/OcelotCustom/README.md b/samples/OcelotCustom/README.md new file mode 100644 index 000000000..ec0fcecb6 --- /dev/null +++ b/samples/OcelotCustom/README.md @@ -0,0 +1,29 @@ +#Example how to use custom service discovery + +This sample constains a simple setup using a custom service discovery provider. + +##Instructions + +1. Get Downstream service running + + ``` + cd ./DownstreamService/ + dotnet run + ``` + + Leave the service running + +2. Get API Gateway running + + ``` + cd ./ApiGateway/ + dotnet run + ``` + + Leave the service running + +3. Make a http request to http://localhost:5000/Category you should get the following response + + ```json + ["category1","category2"] + ``` \ No newline at end of file From f7e9ad92bf5eb4a84fc0a9b631402ff95779b21d Mon Sep 17 00:00:00 2001 From: Raman Maksimchuk Date: Fri, 26 May 2023 15:29:18 +0300 Subject: [PATCH 09/27] Move usings to the top. Use file-scoped namespace declaration --- samples/OcelotCustom/ApiGateway/Program.cs | 85 +++++++++++----------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/samples/OcelotCustom/ApiGateway/Program.cs b/samples/OcelotCustom/ApiGateway/Program.cs index 7977eb031..24e6c1e56 100644 --- a/samples/OcelotCustom/ApiGateway/Program.cs +++ b/samples/OcelotCustom/ApiGateway/Program.cs @@ -1,48 +1,49 @@ -namespace ApiGateway -{ - using ApiGateway.ServiceDiscovery; - using Microsoft.AspNetCore; - using Microsoft.AspNetCore.Hosting; - using Microsoft.Extensions.Configuration; - using Microsoft.Extensions.DependencyInjection; - using Ocelot.DependencyInjection; - using Ocelot.Middleware; - using Ocelot.ServiceDiscovery; - using System; +using ApiGateway.ServiceDiscovery; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +using Ocelot.DependencyInjection; +using Ocelot.Middleware; +using Ocelot.ServiceDiscovery; + +using System; - public class Program +namespace ApiGateway; + +public class Program +{ + public static void Main(string[] args) { - public static void Main(string[] args) - { - BuildWebHost(args).Run(); - } + BuildWebHost(args).Run(); + } - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseUrls("http://localhost:5000") - .ConfigureAppConfiguration((hostingContext, config) => - { - config - .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) - .AddJsonFile("appsettings.json", true, true) - .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true) - .AddJsonFile("ocelot.json", false, false) - .AddEnvironmentVariables(); - }) - .ConfigureServices(s => + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseUrls("http://localhost:5000") + .ConfigureAppConfiguration((hostingContext, config) => + { + config + .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) + .AddJsonFile("appsettings.json", true, true) + .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true) + .AddJsonFile("ocelot.json", false, false) + .AddEnvironmentVariables(); + }) + .ConfigureServices(s => + { + ServiceDiscoveryFinderDelegate serviceDiscoveryFinder = (serviceProvider, config, downstreamRoute) => { - ServiceDiscoveryFinderDelegate serviceDiscoveryFinder = (serviceProvider, config, downstreamRoute) => - { - return new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute); - }; + return new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute); + }; - s.AddSingleton(serviceDiscoveryFinder); - s.AddOcelot(); - }) - .Configure(a => - { - a.UseOcelot().Wait(); - }) - .Build(); - } + s.AddSingleton(serviceDiscoveryFinder); + s.AddOcelot(); + }) + .Configure(a => + { + a.UseOcelot().Wait(); + }) + .Build(); } From 805b92b09833574dbccd749812fe4144758cb6bf Mon Sep 17 00:00:00 2001 From: leonluc-dev Date: Wed, 31 May 2023 14:03:00 +0200 Subject: [PATCH 10/27] Moved custom service discovery sample Added sample to Ocelot.sln --- .../OcelotCustom/ApiGateway/ApiGateway.csproj | 24 --------- samples/OcelotCustom/ApiGateway/Program.cs | 49 ------------------- .../ApiGateway/Properties/launchSettings.json | 27 ---------- .../MyServiceDiscoveryProvider.cs | 45 ----------------- .../OcelotCustom/ApiGateway/appsettings.json | 19 ------- samples/OcelotCustom/ApiGateway/ocelot.json | 19 ------- .../Controllers/CategoryController.cs | 17 ------- .../DownstreamService.csproj | 11 ----- .../OcelotCustom/DownstreamService/Program.cs | 21 -------- .../Properties/launchSettings.json | 29 ----------- .../OcelotCustom/DownstreamService/Startup.cs | 40 --------------- .../appsettings.Development.json | 10 ---- .../DownstreamService/appsettings.json | 16 ------ samples/OcelotCustom/OcelotCustom.sln | 31 ------------ samples/OcelotCustom/README.md | 29 ----------- 15 files changed, 387 deletions(-) delete mode 100644 samples/OcelotCustom/ApiGateway/ApiGateway.csproj delete mode 100644 samples/OcelotCustom/ApiGateway/Program.cs delete mode 100644 samples/OcelotCustom/ApiGateway/Properties/launchSettings.json delete mode 100644 samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs delete mode 100644 samples/OcelotCustom/ApiGateway/appsettings.json delete mode 100644 samples/OcelotCustom/ApiGateway/ocelot.json delete mode 100644 samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs delete mode 100644 samples/OcelotCustom/DownstreamService/DownstreamService.csproj delete mode 100644 samples/OcelotCustom/DownstreamService/Program.cs delete mode 100644 samples/OcelotCustom/DownstreamService/Properties/launchSettings.json delete mode 100644 samples/OcelotCustom/DownstreamService/Startup.cs delete mode 100644 samples/OcelotCustom/DownstreamService/appsettings.Development.json delete mode 100644 samples/OcelotCustom/DownstreamService/appsettings.json delete mode 100644 samples/OcelotCustom/OcelotCustom.sln delete mode 100644 samples/OcelotCustom/README.md diff --git a/samples/OcelotCustom/ApiGateway/ApiGateway.csproj b/samples/OcelotCustom/ApiGateway/ApiGateway.csproj deleted file mode 100644 index 2d7238d54..000000000 --- a/samples/OcelotCustom/ApiGateway/ApiGateway.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net7.0 - - - - - - - - - - - - PreserveNewest - - - - - - - - diff --git a/samples/OcelotCustom/ApiGateway/Program.cs b/samples/OcelotCustom/ApiGateway/Program.cs deleted file mode 100644 index 24e6c1e56..000000000 --- a/samples/OcelotCustom/ApiGateway/Program.cs +++ /dev/null @@ -1,49 +0,0 @@ -using ApiGateway.ServiceDiscovery; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -using Ocelot.DependencyInjection; -using Ocelot.Middleware; -using Ocelot.ServiceDiscovery; - -using System; - -namespace ApiGateway; - -public class Program -{ - public static void Main(string[] args) - { - BuildWebHost(args).Run(); - } - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseUrls("http://localhost:5000") - .ConfigureAppConfiguration((hostingContext, config) => - { - config - .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) - .AddJsonFile("appsettings.json", true, true) - .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true) - .AddJsonFile("ocelot.json", false, false) - .AddEnvironmentVariables(); - }) - .ConfigureServices(s => - { - ServiceDiscoveryFinderDelegate serviceDiscoveryFinder = (serviceProvider, config, downstreamRoute) => - { - return new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute); - }; - - s.AddSingleton(serviceDiscoveryFinder); - s.AddOcelot(); - }) - .Configure(a => - { - a.UseOcelot().Wait(); - }) - .Build(); -} diff --git a/samples/OcelotCustom/ApiGateway/Properties/launchSettings.json b/samples/OcelotCustom/ApiGateway/Properties/launchSettings.json deleted file mode 100644 index c1b4df874..000000000 --- a/samples/OcelotCustom/ApiGateway/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:54060/", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "ApiGateway": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:54061/" - } - } -} diff --git a/samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs b/samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs deleted file mode 100644 index 5f6e02411..000000000 --- a/samples/OcelotCustom/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Ocelot.Configuration; -using Ocelot.ServiceDiscovery.Providers; -using Ocelot.Values; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace ApiGateway.ServiceDiscovery -{ - public class MyServiceDiscoveryProvider : IServiceDiscoveryProvider - { - private readonly IServiceProvider _serviceProvider; - private readonly ServiceProviderConfiguration _config; - private readonly DownstreamRoute _downstreamRoute; - - public MyServiceDiscoveryProvider(IServiceProvider serviceProvider, ServiceProviderConfiguration config, DownstreamRoute downstreamRoute) - { - _serviceProvider = serviceProvider; - _config = config; - _downstreamRoute = downstreamRoute; - } - - public Task> Get() - { - //Returns a list of service(s) that match the downstream route passed to the provider - var services = new List(); - - if(_downstreamRoute.ServiceName.Equals("downstream-service")) - { - //For this example we simply do a manual match to a single service - var service = new Service( - name: "downstream-service", - hostAndPort: new ServiceHostAndPort("localhost", 5001), - id: "downstream-service-1", - version: "1.0", - tags: new string[] { "downstream", "hardcoded" } - ); - - services.Add(service); - } - - return Task.FromResult(services); - } - } -} diff --git a/samples/OcelotCustom/ApiGateway/appsettings.json b/samples/OcelotCustom/ApiGateway/appsettings.json deleted file mode 100644 index 454577ddb..000000000 --- a/samples/OcelotCustom/ApiGateway/appsettings.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "Logging": { - "IncludeScopes": true, - "LogLevel": { - "Default": "Trace", - "System": "Information", - "Microsoft": "Information" - } - }, - "spring": { - "application": { "name": "Ocelot-Gateway" }, - "cloud": { - "config": { - "uri": "http://localhost:5000", - "validateCertificates": false - } - } - } -} diff --git a/samples/OcelotCustom/ApiGateway/ocelot.json b/samples/OcelotCustom/ApiGateway/ocelot.json deleted file mode 100644 index 0b288280e..000000000 --- a/samples/OcelotCustom/ApiGateway/ocelot.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "Routes": [ - { - "DownstreamPathTemplate": "/api/Category", - "DownstreamScheme": "http", - "UpstreamPathTemplate": "/Category", - "ServiceName": "downstream-service", - "UpstreamHttpMethod": [ "Get" ], - "FileCacheOptions": { "TtlSeconds": 15 } - } - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId", - "AdministrationPath": "/administration", - "ServiceDiscoveryProvider": { - "Type": "MyServiceDiscoveryProvider" - } - } -} diff --git a/samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs b/samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs deleted file mode 100644 index 5ce38f475..000000000 --- a/samples/OcelotCustom/DownstreamService/Controllers/CategoryController.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; - -using Microsoft.AspNetCore.Mvc; - -namespace DownstreamService.Controllers -{ - [Route("api/[controller]")] - public class CategoryController : Controller - { - // GET api/values - [HttpGet] - public IEnumerable Get() - { - return new[] { "category1", "category2" }; - } - } -} diff --git a/samples/OcelotCustom/DownstreamService/DownstreamService.csproj b/samples/OcelotCustom/DownstreamService/DownstreamService.csproj deleted file mode 100644 index a4104fc03..000000000 --- a/samples/OcelotCustom/DownstreamService/DownstreamService.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - net7.0 - - - - - - - diff --git a/samples/OcelotCustom/DownstreamService/Program.cs b/samples/OcelotCustom/DownstreamService/Program.cs deleted file mode 100644 index 130b46f0e..000000000 --- a/samples/OcelotCustom/DownstreamService/Program.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; - -namespace DownstreamService -{ - public class Program - { - public static void Main(string[] args) - { - BuildWebHost(args).Run(); - } - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseUrls($"http://{Environment.MachineName}:5001") - .UseStartup() - .Build(); - } -} diff --git a/samples/OcelotCustom/DownstreamService/Properties/launchSettings.json b/samples/OcelotCustom/DownstreamService/Properties/launchSettings.json deleted file mode 100644 index 0c084db8e..000000000 --- a/samples/OcelotCustom/DownstreamService/Properties/launchSettings.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:53908/", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "api/values", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "DownstreamService": { - "commandName": "Project", - "launchBrowser": true, - "launchUrl": "api/values", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:53909/" - } - } -} diff --git a/samples/OcelotCustom/DownstreamService/Startup.cs b/samples/OcelotCustom/DownstreamService/Startup.cs deleted file mode 100644 index af07bc2eb..000000000 --- a/samples/OcelotCustom/DownstreamService/Startup.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -namespace DownstreamService -{ - using Microsoft.Extensions.Hosting; - - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddControllers(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseRouting(); - app.UseEndpoints(configure => - { - configure.MapControllers(); - }); - } - } -} diff --git a/samples/OcelotCustom/DownstreamService/appsettings.Development.json b/samples/OcelotCustom/DownstreamService/appsettings.Development.json deleted file mode 100644 index fa8ce71a9..000000000 --- a/samples/OcelotCustom/DownstreamService/appsettings.Development.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - } -} diff --git a/samples/OcelotCustom/DownstreamService/appsettings.json b/samples/OcelotCustom/DownstreamService/appsettings.json deleted file mode 100644 index 255a1bbcd..000000000 --- a/samples/OcelotCustom/DownstreamService/appsettings.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { "Default": "Warning" } - }, - "spring": { - "application": { "name": "downstream-service" }, - "cloud": { - "config": { - "uri": "http://localhost:5001", - "validate_certificates": false - } - } - } -} - diff --git a/samples/OcelotCustom/OcelotCustom.sln b/samples/OcelotCustom/OcelotCustom.sln deleted file mode 100644 index 62eb6ebc4..000000000 --- a/samples/OcelotCustom/OcelotCustom.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27428.2027 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DownstreamService", "./DownstreamService/DownstreamService.csproj", "{2982C147-9446-47FE-862E-E689B64CC7E7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiGateway", "./ApiGateway/ApiGateway.csproj", "{006CF27E-5400-43E9-B511-C54EC1B9C546}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2982C147-9446-47FE-862E-E689B64CC7E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2982C147-9446-47FE-862E-E689B64CC7E7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2982C147-9446-47FE-862E-E689B64CC7E7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2982C147-9446-47FE-862E-E689B64CC7E7}.Release|Any CPU.Build.0 = Release|Any CPU - {006CF27E-5400-43E9-B511-C54EC1B9C546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {006CF27E-5400-43E9-B511-C54EC1B9C546}.Debug|Any CPU.Build.0 = Debug|Any CPU - {006CF27E-5400-43E9-B511-C54EC1B9C546}.Release|Any CPU.ActiveCfg = Release|Any CPU - {006CF27E-5400-43E9-B511-C54EC1B9C546}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {2C604707-2EA1-4CCF-A89C-22B613052C8D} - EndGlobalSection -EndGlobal diff --git a/samples/OcelotCustom/README.md b/samples/OcelotCustom/README.md deleted file mode 100644 index ec0fcecb6..000000000 --- a/samples/OcelotCustom/README.md +++ /dev/null @@ -1,29 +0,0 @@ -#Example how to use custom service discovery - -This sample constains a simple setup using a custom service discovery provider. - -##Instructions - -1. Get Downstream service running - - ``` - cd ./DownstreamService/ - dotnet run - ``` - - Leave the service running - -2. Get API Gateway running - - ``` - cd ./ApiGateway/ - dotnet run - ``` - - Leave the service running - -3. Make a http request to http://localhost:5000/Category you should get the following response - - ```json - ["category1","category2"] - ``` \ No newline at end of file From 2bc58634a65bb059f08690cdf88d77ff1d0cd987 Mon Sep 17 00:00:00 2001 From: raman-m Date: Fri, 9 Jun 2023 20:13:02 +0300 Subject: [PATCH 11/27] Add 2 options/ways of solution development via ConfigureServices --- .../ApiGateway/Program.cs | 24 +++-- .../MyServiceDiscoveryProvider.cs | 62 ++++++------- .../MyServiceDiscoveryProviderFactory.cs | 31 +++++++ .../ServiceDiscoveryProviderFactory.cs | 90 +++++++++---------- 4 files changed, 121 insertions(+), 86 deletions(-) create mode 100644 samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProviderFactory.cs diff --git a/samples/OcelotServiceDiscovery/ApiGateway/Program.cs b/samples/OcelotServiceDiscovery/ApiGateway/Program.cs index 24e6c1e56..831e37874 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/Program.cs +++ b/samples/OcelotServiceDiscovery/ApiGateway/Program.cs @@ -3,12 +3,10 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; - using Ocelot.DependencyInjection; using Ocelot.Middleware; using Ocelot.ServiceDiscovery; - -using System; +using Ocelot.ServiceDiscovery.Providers; namespace ApiGateway; @@ -33,12 +31,24 @@ public static IWebHost BuildWebHost(string[] args) => }) .ConfigureServices(s => { - ServiceDiscoveryFinderDelegate serviceDiscoveryFinder = (serviceProvider, config, downstreamRoute) => + // Initialize from app configuration or hardcode/choose the best option. + bool easyWay = true; + + if (easyWay) + { + // Option #1. Define custom finder delegate to instantiate custom provider + // by default factory which is ServiceDiscoveryProviderFactory + s.AddSingleton((serviceProvider, config, downstreamRoute) + => new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute)); + } + else { - return new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute); - }; + // Option #2. Abstract from default factory (ServiceDiscoveryProviderFactory) and from FinderDelegate, + // and build custom factory by implementation of the IServiceDiscoveryProviderFactory interface. + s.AddScoped(); + s.AddScoped(); + } - s.AddSingleton(serviceDiscoveryFinder); s.AddOcelot(); }) .Configure(a => diff --git a/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs b/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs index 5f6e02411..7eab3636a 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs +++ b/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs @@ -5,41 +5,43 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace ApiGateway.ServiceDiscovery +namespace ApiGateway.ServiceDiscovery; + +public class MyServiceDiscoveryProvider : IServiceDiscoveryProvider { - public class MyServiceDiscoveryProvider : IServiceDiscoveryProvider + private readonly IServiceProvider _serviceProvider; + private readonly ServiceProviderConfiguration _config; + private readonly DownstreamRoute _downstreamRoute; + + public MyServiceDiscoveryProvider(IServiceProvider serviceProvider, ServiceProviderConfiguration config, DownstreamRoute downstreamRoute) { - private readonly IServiceProvider _serviceProvider; - private readonly ServiceProviderConfiguration _config; - private readonly DownstreamRoute _downstreamRoute; + _serviceProvider = serviceProvider; + _config = config; + _downstreamRoute = downstreamRoute; + } - public MyServiceDiscoveryProvider(IServiceProvider serviceProvider, ServiceProviderConfiguration config, DownstreamRoute downstreamRoute) - { - _serviceProvider = serviceProvider; - _config = config; - _downstreamRoute = downstreamRoute; - } + public Task> Get() + { + + // Returns a list of service(s) that match the downstream route passed to the provider + var services = new List(); - public Task> Get() + // Apply configuration checks + // ... if (_config.Host) + if (_downstreamRoute.ServiceName.Equals("downstream-service")) { - //Returns a list of service(s) that match the downstream route passed to the provider - var services = new List(); - - if(_downstreamRoute.ServiceName.Equals("downstream-service")) - { - //For this example we simply do a manual match to a single service - var service = new Service( - name: "downstream-service", - hostAndPort: new ServiceHostAndPort("localhost", 5001), - id: "downstream-service-1", - version: "1.0", - tags: new string[] { "downstream", "hardcoded" } - ); - - services.Add(service); - } - - return Task.FromResult(services); + //For this example we simply do a manual match to a single service + var service = new Service( + name: "downstream-service", + hostAndPort: new ServiceHostAndPort("localhost", 5001), + id: "downstream-service-1", + version: "1.0", + tags: new string[] { "downstream", "hardcoded" } + ); + + services.Add(service); } + + return Task.FromResult(services); } } diff --git a/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProviderFactory.cs b/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProviderFactory.cs new file mode 100644 index 000000000..6f3462680 --- /dev/null +++ b/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProviderFactory.cs @@ -0,0 +1,31 @@ +using Ocelot.Configuration; +using Ocelot.Logging; +using Ocelot.Responses; +using Ocelot.ServiceDiscovery; +using Ocelot.ServiceDiscovery.Providers; +using System; + +namespace ApiGateway.ServiceDiscovery; + +public class MyServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory +{ + private readonly IOcelotLoggerFactory _factory; + private readonly IServiceProvider _provider; + + public MyServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IServiceProvider provider) + { + _factory = factory; + _provider = provider; + } + + public Response Get(ServiceProviderConfiguration serviceConfig, DownstreamRoute route) + { + // Apply configuration checks + // ... + + // Create the provider based on configuration and route info + var provider = new MyServiceDiscoveryProvider(_provider, serviceConfig, route); + + return new OkResponse(provider); + } +} diff --git a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs index ed04c3532..ed2324460 100644 --- a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs +++ b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs @@ -1,73 +1,65 @@ -using System; -using System.Collections.Generic; - -using Ocelot.ServiceDiscovery.Configuration; - -using Ocelot.Logging; - using Microsoft.Extensions.DependencyInjection; - using Ocelot.Configuration; - -using Ocelot.ServiceDiscovery.Providers; - +using Ocelot.Logging; using Ocelot.Responses; - +using Ocelot.ServiceDiscovery.Configuration; +using Ocelot.ServiceDiscovery.Providers; using Ocelot.Values; +using System; +using System.Collections.Generic; -namespace Ocelot.ServiceDiscovery +namespace Ocelot.ServiceDiscovery; + +public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory { - public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory + private readonly IOcelotLoggerFactory _factory; + private readonly ServiceDiscoveryFinderDelegate _delegates; + private readonly IServiceProvider _provider; + + public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IServiceProvider provider) { - private readonly IOcelotLoggerFactory _factory; - private readonly ServiceDiscoveryFinderDelegate _delegates; - private readonly IServiceProvider _provider; + _factory = factory; + _provider = provider; + _delegates = provider.GetService(); + } - public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IServiceProvider provider) + public Response Get(ServiceProviderConfiguration serviceConfig, DownstreamRoute route) + { + if (route.UseServiceDiscovery) { - _factory = factory; - _provider = provider; - _delegates = provider.GetService(); + return GetServiceDiscoveryProvider(serviceConfig, route); } - public Response Get(ServiceProviderConfiguration serviceConfig, DownstreamRoute route) - { - if (route.UseServiceDiscovery) - { - return GetServiceDiscoveryProvider(serviceConfig, route); - } + var services = new List(); - var services = new List(); + foreach (var downstreamAddress in route.DownstreamAddresses) + { + var service = new Service(route.ServiceName, new ServiceHostAndPort(downstreamAddress.Host, downstreamAddress.Port, route.DownstreamScheme), string.Empty, string.Empty, Array.Empty()); - foreach (var downstreamAddress in route.DownstreamAddresses) - { - var service = new Service(route.ServiceName, new ServiceHostAndPort(downstreamAddress.Host, downstreamAddress.Port, route.DownstreamScheme), string.Empty, string.Empty, Array.Empty()); + services.Add(service); + } - services.Add(service); - } + return new OkResponse(new ConfigurationServiceProvider(services)); + } - return new OkResponse(new ConfigurationServiceProvider(services)); + private Response GetServiceDiscoveryProvider(ServiceProviderConfiguration config, DownstreamRoute route) + { + if (config.Type?.ToLower() == "servicefabric") + { + var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, route.ServiceName); + return new OkResponse(new ServiceFabricServiceDiscoveryProvider(sfConfig)); } - private Response GetServiceDiscoveryProvider(ServiceProviderConfiguration config, DownstreamRoute route) + if (_delegates != null) { - if (config.Type?.ToLower() == "servicefabric") - { - var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, route.ServiceName); - return new OkResponse(new ServiceFabricServiceDiscoveryProvider(sfConfig)); - } + var provider = _delegates?.Invoke(_provider, config, route); - if (_delegates != null) + if (provider.GetType().Name.ToLower() == config.Type.ToLower()) { - var provider = _delegates?.Invoke(_provider, config, route); - - if (provider.GetType().Name.ToLower() == config.Type.ToLower()) - { - return new OkResponse(provider); - } + return new OkResponse(provider); } - - return new ErrorResponse(new UnableToFindServiceDiscoveryProviderError($"Unable to find service discovery provider for type: {config.Type}")); } + + return new ErrorResponse(new UnableToFindServiceDiscoveryProviderError($"Unable to find service discovery provider for type: {config.Type}")); } } From 9446149229a550f42f7423d5ac9c9067ced24e01 Mon Sep 17 00:00:00 2001 From: raman-m Date: Sat, 10 Jun 2023 19:58:37 +0300 Subject: [PATCH 12/27] Upgrade DownstreamService to ASP.NET 7 --- Ocelot.sln | 2 +- .../Controllers/CategoryController.cs | 20 +++-- ...ServiceDiscovery.DownstreamService.csproj} | 4 + .../DownstreamService/Program.cs | 28 ++++--- .../Properties/launchSettings.json | 6 +- .../DownstreamService/Startup.cs | 73 +++++++++++++------ 6 files changed, 79 insertions(+), 54 deletions(-) rename samples/OcelotServiceDiscovery/DownstreamService/{DownstreamService.csproj => Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj} (72%) diff --git a/Ocelot.sln b/Ocelot.sln index e13fc798a..d311b5c68 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -90,7 +90,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "service-discovery", "servic EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiGateway", "samples\OcelotServiceDiscovery\ApiGateway\ApiGateway.csproj", "{D37209EA-C13E-42AE-B851-A8604F1FCD0E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DownstreamService", "samples\OcelotServiceDiscovery\DownstreamService\DownstreamService.csproj", "{E2AC741A-4120-4D59-B5E4-16382ED45E8D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Samples.ServiceDiscovery.DownstreamService", "samples\OcelotServiceDiscovery\DownstreamService\Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj", "{E2AC741A-4120-4D59-B5E4-16382ED45E8D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs index 5ce38f475..ea2666f3a 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs +++ b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs @@ -1,17 +1,15 @@ -using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; -using Microsoft.AspNetCore.Mvc; +namespace Ocelot.Samples.ServiceDiscovery.DownstreamService.Controllers; -namespace DownstreamService.Controllers +[Route("api/[controller]")] +public class CategoriesController : Controller { - [Route("api/[controller]")] - public class CategoryController : Controller + // GET api/categories + [HttpGet] + public IEnumerable Get() { - // GET api/values - [HttpGet] - public IEnumerable Get() - { - return new[] { "category1", "category2" }; - } + return new[] { "category1", "category2" }; } } diff --git a/samples/OcelotServiceDiscovery/DownstreamService/DownstreamService.csproj b/samples/OcelotServiceDiscovery/DownstreamService/Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj similarity index 72% rename from samples/OcelotServiceDiscovery/DownstreamService/DownstreamService.csproj rename to samples/OcelotServiceDiscovery/DownstreamService/Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj index a4104fc03..76b215ada 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/DownstreamService.csproj +++ b/samples/OcelotServiceDiscovery/DownstreamService/Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj @@ -8,4 +8,8 @@ + + + + diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Program.cs b/samples/OcelotServiceDiscovery/DownstreamService/Program.cs index 130b46f0e..7fd1a37c8 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Program.cs +++ b/samples/OcelotServiceDiscovery/DownstreamService/Program.cs @@ -1,21 +1,19 @@ -using System; - -using Microsoft.AspNetCore; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; +using System; + +namespace Ocelot.Samples.ServiceDiscovery.DownstreamService; -namespace DownstreamService +public class Program { - public class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - BuildWebHost(args).Run(); - } - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseUrls($"http://{Environment.MachineName}:5001") - .UseStartup() - .Build(); + BuildWebHost(args).Run(); } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseUrls($"http://{Environment.MachineName}:5001") + .UseStartup() + .Build(); } diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Properties/launchSettings.json b/samples/OcelotServiceDiscovery/DownstreamService/Properties/launchSettings.json index 0c084db8e..261fa52ec 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Properties/launchSettings.json +++ b/samples/OcelotServiceDiscovery/DownstreamService/Properties/launchSettings.json @@ -11,7 +11,7 @@ "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, - "launchUrl": "api/values", + "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } @@ -19,11 +19,11 @@ "DownstreamService": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "api/values", + "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "applicationUrl": "http://localhost:53909/" + "applicationUrl": "http://localhost:5001/" } } } diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Startup.cs b/samples/OcelotServiceDiscovery/DownstreamService/Startup.cs index af07bc2eb..b541e186d 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Startup.cs +++ b/samples/OcelotServiceDiscovery/DownstreamService/Startup.cs @@ -2,39 +2,64 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System.Text.Json; +using System.Text.Json.Serialization; -namespace DownstreamService +namespace Ocelot.Samples.ServiceDiscovery.DownstreamService; + +public class Startup { - using Microsoft.Extensions.Hosting; + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } - public class Startup + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } + services + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + .AddEndpointsApiExplorer() + .AddSwaggerGen() - public IConfiguration Configuration { get; } + .AddControllers() + .AddJsonOptions(options => + { + options.AllowInputFormatterExceptionMessages = true; + var jOptions = options.JsonSerializerOptions; + jOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase, true)); + jOptions.PropertyNameCaseInsensitive = true; + jOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }); - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) + AddApplicationServices(services); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) { - services.AddControllers(); + app.UseDeveloperExceptionPage(); + app.UseSwagger(); + app.UseSwaggerUI(); } - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + app.UseRouting(); + app.UseEndpoints(configure => { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseRouting(); - app.UseEndpoints(configure => - { - configure.MapControllers(); - }); - } + configure.MapControllers(); + }); + } + + private static void AddApplicationServices(IServiceCollection services) + { + services.AddHttpClient(); // to keep performance of HTTP Client high + //services.AddSingleton + //services.AddScoped + //services.AddTransient } } From ebf69f29c4dad4316e7df2b997b960a41e820984 Mon Sep 17 00:00:00 2001 From: raman-m Date: Sat, 10 Jun 2023 21:09:45 +0300 Subject: [PATCH 13/27] Upgrade ApiGateway to ASP.NET 7 --- Ocelot.sln | 4 +-- .../ApiGateway/ApiGateway.csproj | 24 -------------- ...Samples.ServiceDiscovery.ApiGateway.csproj | 11 +++++++ .../ApiGateway/Program.cs | 7 +++-- .../ApiGateway/Properties/launchSettings.json | 3 +- .../MyServiceDiscoveryProvider.cs | 2 +- .../MyServiceDiscoveryProviderFactory.cs | 2 +- .../ApiGateway/appsettings.json | 2 +- .../ApiGateway/ocelot.json | 4 +-- .../Ocelot.Samples.ServiceDiscovery.sln | 31 +++++++++++++++++++ .../OcelotServiceDiscovery.sln | 31 ------------------- samples/OcelotServiceDiscovery/README.md | 4 +-- 12 files changed, 57 insertions(+), 68 deletions(-) delete mode 100644 samples/OcelotServiceDiscovery/ApiGateway/ApiGateway.csproj create mode 100644 samples/OcelotServiceDiscovery/ApiGateway/Ocelot.Samples.ServiceDiscovery.ApiGateway.csproj create mode 100644 samples/OcelotServiceDiscovery/Ocelot.Samples.ServiceDiscovery.sln delete mode 100644 samples/OcelotServiceDiscovery/OcelotServiceDiscovery.sln diff --git a/Ocelot.sln b/Ocelot.sln index d311b5c68..8ed0e2067 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.0.32112.339 +VisualStudioVersion = 17.6.33723.286 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5CFB79B7-C9DC-45A4-9A75-625D92471702}" EndProject @@ -88,7 +88,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OcelotOpenTracing", "sample EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "service-discovery", "service-discovery", "{25C30AAA-12DD-4BA5-A53F-9271E54EBAB7}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiGateway", "samples\OcelotServiceDiscovery\ApiGateway\ApiGateway.csproj", "{D37209EA-C13E-42AE-B851-A8604F1FCD0E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Samples.ServiceDiscovery.ApiGateway", "samples\OcelotServiceDiscovery\ApiGateway\Ocelot.Samples.ServiceDiscovery.ApiGateway.csproj", "{D37209EA-C13E-42AE-B851-A8604F1FCD0E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Samples.ServiceDiscovery.DownstreamService", "samples\OcelotServiceDiscovery\DownstreamService\Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj", "{E2AC741A-4120-4D59-B5E4-16382ED45E8D}" EndProject diff --git a/samples/OcelotServiceDiscovery/ApiGateway/ApiGateway.csproj b/samples/OcelotServiceDiscovery/ApiGateway/ApiGateway.csproj deleted file mode 100644 index 2d7238d54..000000000 --- a/samples/OcelotServiceDiscovery/ApiGateway/ApiGateway.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net7.0 - - - - - - - - - - - - PreserveNewest - - - - - - - - diff --git a/samples/OcelotServiceDiscovery/ApiGateway/Ocelot.Samples.ServiceDiscovery.ApiGateway.csproj b/samples/OcelotServiceDiscovery/ApiGateway/Ocelot.Samples.ServiceDiscovery.ApiGateway.csproj new file mode 100644 index 000000000..e987ea143 --- /dev/null +++ b/samples/OcelotServiceDiscovery/ApiGateway/Ocelot.Samples.ServiceDiscovery.ApiGateway.csproj @@ -0,0 +1,11 @@ + + + + net7.0 + + + + + + + diff --git a/samples/OcelotServiceDiscovery/ApiGateway/Program.cs b/samples/OcelotServiceDiscovery/ApiGateway/Program.cs index 831e37874..11b363979 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/Program.cs +++ b/samples/OcelotServiceDiscovery/ApiGateway/Program.cs @@ -1,5 +1,4 @@ -using ApiGateway.ServiceDiscovery; -using Microsoft.AspNetCore; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -8,7 +7,9 @@ using Ocelot.ServiceDiscovery; using Ocelot.ServiceDiscovery.Providers; -namespace ApiGateway; +namespace Ocelot.Samples.ServiceDiscovery.ApiGateway; + +using ServiceDiscovery; public class Program { diff --git a/samples/OcelotServiceDiscovery/ApiGateway/Properties/launchSettings.json b/samples/OcelotServiceDiscovery/ApiGateway/Properties/launchSettings.json index c1b4df874..201001499 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/Properties/launchSettings.json +++ b/samples/OcelotServiceDiscovery/ApiGateway/Properties/launchSettings.json @@ -18,10 +18,11 @@ "ApiGateway": { "commandName": "Project", "launchBrowser": true, + "launchUrl": "Categories", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "applicationUrl": "http://localhost:54061/" + "applicationUrl": "http://localhost:5000/" } } } diff --git a/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs b/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs index 7eab3636a..76e655bd1 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs +++ b/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProvider.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace ApiGateway.ServiceDiscovery; +namespace Ocelot.Samples.ServiceDiscovery.ApiGateway.ServiceDiscovery; public class MyServiceDiscoveryProvider : IServiceDiscoveryProvider { diff --git a/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProviderFactory.cs b/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProviderFactory.cs index 6f3462680..1978ebd3d 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProviderFactory.cs +++ b/samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery/MyServiceDiscoveryProviderFactory.cs @@ -5,7 +5,7 @@ using Ocelot.ServiceDiscovery.Providers; using System; -namespace ApiGateway.ServiceDiscovery; +namespace Ocelot.Samples.ServiceDiscovery.ApiGateway.ServiceDiscovery; public class MyServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory { diff --git a/samples/OcelotServiceDiscovery/ApiGateway/appsettings.json b/samples/OcelotServiceDiscovery/ApiGateway/appsettings.json index 454577ddb..e4415969b 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/appsettings.json +++ b/samples/OcelotServiceDiscovery/ApiGateway/appsettings.json @@ -2,7 +2,7 @@ "Logging": { "IncludeScopes": true, "LogLevel": { - "Default": "Trace", + "Default": "Information", "System": "Information", "Microsoft": "Information" } diff --git a/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json b/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json index 0b288280e..3f6846147 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json +++ b/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json @@ -1,9 +1,9 @@ { "Routes": [ { - "DownstreamPathTemplate": "/api/Category", + "DownstreamPathTemplate": "/api/Categories", "DownstreamScheme": "http", - "UpstreamPathTemplate": "/Category", + "UpstreamPathTemplate": "/Categories", "ServiceName": "downstream-service", "UpstreamHttpMethod": [ "Get" ], "FileCacheOptions": { "TtlSeconds": 15 } diff --git a/samples/OcelotServiceDiscovery/Ocelot.Samples.ServiceDiscovery.sln b/samples/OcelotServiceDiscovery/Ocelot.Samples.ServiceDiscovery.sln new file mode 100644 index 000000000..299c18b54 --- /dev/null +++ b/samples/OcelotServiceDiscovery/Ocelot.Samples.ServiceDiscovery.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33723.286 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Samples.ServiceDiscovery.ApiGateway", "ApiGateway\Ocelot.Samples.ServiceDiscovery.ApiGateway.csproj", "{411000B6-ACB0-4323-8FE4-A4DE0E590ACB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Samples.ServiceDiscovery.DownstreamService", "DownstreamService\Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj", "{4F302EAE-1C67-47CA-ACCE-D05DF00AAAC1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {411000B6-ACB0-4323-8FE4-A4DE0E590ACB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {411000B6-ACB0-4323-8FE4-A4DE0E590ACB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {411000B6-ACB0-4323-8FE4-A4DE0E590ACB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {411000B6-ACB0-4323-8FE4-A4DE0E590ACB}.Release|Any CPU.Build.0 = Release|Any CPU + {4F302EAE-1C67-47CA-ACCE-D05DF00AAAC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F302EAE-1C67-47CA-ACCE-D05DF00AAAC1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F302EAE-1C67-47CA-ACCE-D05DF00AAAC1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F302EAE-1C67-47CA-ACCE-D05DF00AAAC1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2C604707-2EA1-4CCF-A89C-22B613052C8D} + EndGlobalSection +EndGlobal diff --git a/samples/OcelotServiceDiscovery/OcelotServiceDiscovery.sln b/samples/OcelotServiceDiscovery/OcelotServiceDiscovery.sln deleted file mode 100644 index 78a246b63..000000000 --- a/samples/OcelotServiceDiscovery/OcelotServiceDiscovery.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.4.33122.133 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DownstreamService", "./DownstreamService/DownstreamService.csproj", "{2982C147-9446-47FE-862E-E689B64CC7E7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiGateway", "./ApiGateway/ApiGateway.csproj", "{006CF27E-5400-43E9-B511-C54EC1B9C546}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2982C147-9446-47FE-862E-E689B64CC7E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2982C147-9446-47FE-862E-E689B64CC7E7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2982C147-9446-47FE-862E-E689B64CC7E7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2982C147-9446-47FE-862E-E689B64CC7E7}.Release|Any CPU.Build.0 = Release|Any CPU - {006CF27E-5400-43E9-B511-C54EC1B9C546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {006CF27E-5400-43E9-B511-C54EC1B9C546}.Debug|Any CPU.Build.0 = Debug|Any CPU - {006CF27E-5400-43E9-B511-C54EC1B9C546}.Release|Any CPU.ActiveCfg = Release|Any CPU - {006CF27E-5400-43E9-B511-C54EC1B9C546}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {2C604707-2EA1-4CCF-A89C-22B613052C8D} - EndGlobalSection -EndGlobal diff --git a/samples/OcelotServiceDiscovery/README.md b/samples/OcelotServiceDiscovery/README.md index ec0fcecb6..aa719b955 100644 --- a/samples/OcelotServiceDiscovery/README.md +++ b/samples/OcelotServiceDiscovery/README.md @@ -22,8 +22,8 @@ This sample constains a simple setup using a custom service discovery provider. Leave the service running -3. Make a http request to http://localhost:5000/Category you should get the following response +3. Make a http request to http://localhost:5000/Categories you should get the following response ```json ["category1","category2"] - ``` \ No newline at end of file + ``` From 38d8b915b510508651b111a1abbb6dc2ef851a59 Mon Sep 17 00:00:00 2001 From: Raman Maksimchuk Date: Sat, 10 Jun 2023 22:23:00 +0300 Subject: [PATCH 14/27] Update README.md --- samples/OcelotServiceDiscovery/README.md | 53 ++++++++++++------------ 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/samples/OcelotServiceDiscovery/README.md b/samples/OcelotServiceDiscovery/README.md index aa719b955..49f14a2a3 100644 --- a/samples/OcelotServiceDiscovery/README.md +++ b/samples/OcelotServiceDiscovery/README.md @@ -1,29 +1,30 @@ -#Example how to use custom service discovery +# Ocelot Service Discovery Custom Provider +> An example how to build custom service discovery in Ocelot.
+> **Documentation**: [Service Discovery](../../docs/features/servicediscovery.rst) > [Custom Providers](../../docs/features/servicediscovery.rst#custom-providers) -This sample constains a simple setup using a custom service discovery provider. +This sample constains a basic setup using a custom service discovery provider.
-##Instructions +## Instructions -1. Get Downstream service running - - ``` - cd ./DownstreamService/ - dotnet run - ``` - - Leave the service running - -2. Get API Gateway running - - ``` - cd ./ApiGateway/ - dotnet run - ``` - - Leave the service running - -3. Make a http request to http://localhost:5000/Categories you should get the following response - - ```json - ["category1","category2"] - ``` +### 1. Run Downstream Service app +```shell +cd ./DownstreamService/ +dotnet run +``` +Leave the service running. + +### 2. Run API Gateway app +```shell +cd ./ApiGateway/ +dotnet run +``` +Leave the gateway running. + +### 3. Make a HTTP request +To the URL: http://localhost:5000/Categories
+You should get the following response: +```json +{ + [ "category1", "category2" ] +} +``` From 6f51bdaabafd2697c4000a2b088e4cd30a414cca Mon Sep 17 00:00:00 2001 From: leonluc-dev Date: Tue, 20 Jun 2023 18:19:08 +0200 Subject: [PATCH 15/27] Removed redundant spring section in config Move urls config from Program.cs to appsettings.json --- samples/OcelotServiceDiscovery/ApiGateway/Program.cs | 1 - .../OcelotServiceDiscovery/ApiGateway/appsettings.json | 10 +--------- ...t.Samples.ServiceDiscovery.DownstreamService.csproj | 4 ---- .../DownstreamService/Program.cs | 1 - .../DownstreamService/appsettings.json | 10 +--------- 5 files changed, 2 insertions(+), 24 deletions(-) diff --git a/samples/OcelotServiceDiscovery/ApiGateway/Program.cs b/samples/OcelotServiceDiscovery/ApiGateway/Program.cs index 11b363979..e9aef24f4 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/Program.cs +++ b/samples/OcelotServiceDiscovery/ApiGateway/Program.cs @@ -20,7 +20,6 @@ public static void Main(string[] args) public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) - .UseUrls("http://localhost:5000") .ConfigureAppConfiguration((hostingContext, config) => { config diff --git a/samples/OcelotServiceDiscovery/ApiGateway/appsettings.json b/samples/OcelotServiceDiscovery/ApiGateway/appsettings.json index e4415969b..9c1fbf602 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/appsettings.json +++ b/samples/OcelotServiceDiscovery/ApiGateway/appsettings.json @@ -7,13 +7,5 @@ "Microsoft": "Information" } }, - "spring": { - "application": { "name": "Ocelot-Gateway" }, - "cloud": { - "config": { - "uri": "http://localhost:5000", - "validateCertificates": false - } - } - } + "Urls": "http://localhost:5000" } diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj b/samples/OcelotServiceDiscovery/DownstreamService/Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj index 76b215ada..aee1bfae0 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj +++ b/samples/OcelotServiceDiscovery/DownstreamService/Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj @@ -4,10 +4,6 @@ net7.0 - - - - diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Program.cs b/samples/OcelotServiceDiscovery/DownstreamService/Program.cs index 7fd1a37c8..068f24a1f 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Program.cs +++ b/samples/OcelotServiceDiscovery/DownstreamService/Program.cs @@ -13,7 +13,6 @@ public static void Main(string[] args) public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) - .UseUrls($"http://{Environment.MachineName}:5001") .UseStartup() .Build(); } diff --git a/samples/OcelotServiceDiscovery/DownstreamService/appsettings.json b/samples/OcelotServiceDiscovery/DownstreamService/appsettings.json index 255a1bbcd..cc7d4c2a6 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/appsettings.json +++ b/samples/OcelotServiceDiscovery/DownstreamService/appsettings.json @@ -3,14 +3,6 @@ "IncludeScopes": false, "LogLevel": { "Default": "Warning" } }, - "spring": { - "application": { "name": "downstream-service" }, - "cloud": { - "config": { - "uri": "http://localhost:5001", - "validate_certificates": false - } - } - } + "Urls": "http://localhost:5001" } From 0a34cb5d453b3b9e12f3b0e522af8c85d3ea40a3 Mon Sep 17 00:00:00 2001 From: raman-m Date: Wed, 21 Jun 2023 13:46:56 +0300 Subject: [PATCH 16/27] Workaround for the Categories route --- .../ApiGateway/Properties/launchSettings.json | 2 +- .../OcelotServiceDiscovery/ApiGateway/ocelot.json | 4 ++-- .../Controllers/CategoryController.cs | 14 +++++++++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/samples/OcelotServiceDiscovery/ApiGateway/Properties/launchSettings.json b/samples/OcelotServiceDiscovery/ApiGateway/Properties/launchSettings.json index 201001499..4262362b0 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/Properties/launchSettings.json +++ b/samples/OcelotServiceDiscovery/ApiGateway/Properties/launchSettings.json @@ -18,7 +18,7 @@ "ApiGateway": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "Categories", + "launchUrl": "categories", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json b/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json index 3f6846147..868c99a64 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json +++ b/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json @@ -1,9 +1,9 @@ { "Routes": [ { - "DownstreamPathTemplate": "/api/Categories", + "DownstreamPathTemplate": "/api/categories", "DownstreamScheme": "http", - "UpstreamPathTemplate": "/Categories", + "UpstreamPathTemplate": "/categories", "ServiceName": "downstream-service", "UpstreamHttpMethod": [ "Get" ], "FileCacheOptions": { "TtlSeconds": 15 } diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs index ea2666f3a..9b1564cc7 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs +++ b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using System; using System.Collections.Generic; namespace Ocelot.Samples.ServiceDiscovery.DownstreamService.Controllers; @@ -10,6 +11,17 @@ public class CategoriesController : Controller [HttpGet] public IEnumerable Get() { - return new[] { "category1", "category2" }; + var random = new Random(); + int max = DateTime.Now.Second; + int length = random.Next(max); + var categories = new List(length); + for (int i = 0; i < length; i++) + { + max = DateTime.Now.Millisecond < 3 + ? DateTime.Now.Millisecond + 3 : DateTime.Now.Millisecond; + categories.Add("category" + random.Next(max)); + } + + return categories; } } From 36d5c5c4d7d20f2256dcc20f212a15c22d4dacaf Mon Sep 17 00:00:00 2001 From: raman-m Date: Wed, 21 Jun 2023 13:51:41 +0300 Subject: [PATCH 17/27] Rename controller: class name should be the same as file name --- .../{CategoryController.cs => CategoriesController.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename samples/OcelotServiceDiscovery/DownstreamService/Controllers/{CategoryController.cs => CategoriesController.cs} (100%) diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoriesController.cs similarity index 100% rename from samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoryController.cs rename to samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoriesController.cs From 4e56f42754733244f24e952f32bb029b6f66ac8e Mon Sep 17 00:00:00 2001 From: raman-m Date: Wed, 21 Jun 2023 17:30:43 +0300 Subject: [PATCH 18/27] Upgrade to Web API app: multiple startup profiles, add Docker profile. Basic microservices template --- samples/OcelotServiceDiscovery/.dockerignore | 25 +++++++++ .../ApiGateway/ocelot.json | 2 +- .../DownstreamService/.dockerignore | 25 +++++++++ .../Controllers/CategoriesController.cs | 13 ++--- .../Controllers/HealthController.cs | 51 +++++++++++++++++++ .../Controllers/WeatherForecastController.cs | 32 ++++++++++++ .../DownstreamService/Dockerfile | 22 ++++++++ .../DownstreamService/Models/HealthResult.cs | 6 +++ .../Models/MicroserviceResult.cs | 6 +++ .../DownstreamService/Models/ReadyResult.cs | 10 ++++ .../Models/WeatherForecast.cs | 12 +++++ ....ServiceDiscovery.DownstreamService.csproj | 9 +++- .../DownstreamService/Program.cs | 15 +++--- .../Properties/launchSettings.json | 45 +++++++++++----- .../DownstreamService/Startup.cs | 13 +++-- .../appsettings.Development.json | 6 +-- .../DownstreamService/appsettings.json | 9 ++-- 17 files changed, 255 insertions(+), 46 deletions(-) create mode 100644 samples/OcelotServiceDiscovery/.dockerignore create mode 100644 samples/OcelotServiceDiscovery/DownstreamService/.dockerignore create mode 100644 samples/OcelotServiceDiscovery/DownstreamService/Controllers/HealthController.cs create mode 100644 samples/OcelotServiceDiscovery/DownstreamService/Controllers/WeatherForecastController.cs create mode 100644 samples/OcelotServiceDiscovery/DownstreamService/Dockerfile create mode 100644 samples/OcelotServiceDiscovery/DownstreamService/Models/HealthResult.cs create mode 100644 samples/OcelotServiceDiscovery/DownstreamService/Models/MicroserviceResult.cs create mode 100644 samples/OcelotServiceDiscovery/DownstreamService/Models/ReadyResult.cs create mode 100644 samples/OcelotServiceDiscovery/DownstreamService/Models/WeatherForecast.cs diff --git a/samples/OcelotServiceDiscovery/.dockerignore b/samples/OcelotServiceDiscovery/.dockerignore new file mode 100644 index 000000000..3729ff0cd --- /dev/null +++ b/samples/OcelotServiceDiscovery/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json b/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json index 868c99a64..7460dcc2a 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json +++ b/samples/OcelotServiceDiscovery/ApiGateway/ocelot.json @@ -1,7 +1,7 @@ { "Routes": [ { - "DownstreamPathTemplate": "/api/categories", + "DownstreamPathTemplate": "/categories", "DownstreamScheme": "http", "UpstreamPathTemplate": "/categories", "ServiceName": "downstream-service", diff --git a/samples/OcelotServiceDiscovery/DownstreamService/.dockerignore b/samples/OcelotServiceDiscovery/DownstreamService/.dockerignore new file mode 100644 index 000000000..3729ff0cd --- /dev/null +++ b/samples/OcelotServiceDiscovery/DownstreamService/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoriesController.cs b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoriesController.cs index 9b1564cc7..7cb6860f2 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoriesController.cs +++ b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/CategoriesController.cs @@ -1,13 +1,10 @@ -using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; +namespace Ocelot.Samples.ServiceDiscovery.DownstreamService.Controllers; -namespace Ocelot.Samples.ServiceDiscovery.DownstreamService.Controllers; - -[Route("api/[controller]")] -public class CategoriesController : Controller +[ApiController] +[Route("[controller]")] +public class CategoriesController : ControllerBase { - // GET api/categories + // GET /categories [HttpGet] public IEnumerable Get() { diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Controllers/HealthController.cs b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/HealthController.cs new file mode 100644 index 000000000..3d351e461 --- /dev/null +++ b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/HealthController.cs @@ -0,0 +1,51 @@ +using System.Reflection; + +namespace Ocelot.Samples.ServiceDiscovery.DownstreamService.Controllers; + +using Models; + +[ApiController] +[Route("[controller]")] +public class HealthController : ControllerBase +{ + private static readonly DateTime startedAt = DateTime.Now; + private static readonly Assembly assembly = Assembly.GetExecutingAssembly(); + + // GET /health + [HttpGet] + [Route("/health", Name = nameof(Health))] + public MicroserviceResult Health() + { + // Analyze integrated services, get their health and return the Health flag + bool isHealthy = true; + + // Get the link of the first action of current microservice workflow + var link = Url.RouteUrl(routeName: "GetWeatherForecast", values: null, protocol: Request.Scheme); + + return new HealthResult + { + Healthy = isHealthy, + Next = new Uri(link), + }; + } + + // GET /ready + [HttpGet] + [Route("/ready", Name = nameof(Ready))] + public MicroserviceResult Ready() + { + var asmName = assembly.GetName(); + + //var link = Url.Action(action: nameof(Health), controller: nameof(Health), values: null, protocol: Request.Scheme); + //var link = Url.RouteUrl(routeName: nameof(Health), values: null, protocol: Request.Scheme); + var link = Url.Link(nameof(Health), null); + + return new ReadyResult + { + ServiceName = asmName.Name, + ServiceVersion = asmName.Version.ToString(), + StartedAt = startedAt, + Next = new Uri(link), + }; + } +} diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Controllers/WeatherForecastController.cs b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/WeatherForecastController.cs new file mode 100644 index 000000000..2576dec59 --- /dev/null +++ b/samples/OcelotServiceDiscovery/DownstreamService/Controllers/WeatherForecastController.cs @@ -0,0 +1,32 @@ +namespace Ocelot.Samples.ServiceDiscovery.DownstreamService.Controllers; + +using Models; + +[ApiController] +[Route("[controller]")] +public class WeatherForecastController : ControllerBase +{ + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } +} diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Dockerfile b/samples/OcelotServiceDiscovery/DownstreamService/Dockerfile new file mode 100644 index 000000000..b7535cfcd --- /dev/null +++ b/samples/OcelotServiceDiscovery/DownstreamService/Dockerfile @@ -0,0 +1,22 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +WORKDIR /src +COPY ["Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj", "."] +RUN dotnet restore "./Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj" +COPY . . +WORKDIR "/src/." +RUN dotnet build "Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Ocelot.Samples.ServiceDiscovery.DownstreamService.dll"] diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Models/HealthResult.cs b/samples/OcelotServiceDiscovery/DownstreamService/Models/HealthResult.cs new file mode 100644 index 000000000..3d017443a --- /dev/null +++ b/samples/OcelotServiceDiscovery/DownstreamService/Models/HealthResult.cs @@ -0,0 +1,6 @@ +namespace Ocelot.Samples.ServiceDiscovery.DownstreamService.Models; + +public class HealthResult : MicroserviceResult +{ + public bool Healthy { get; set; } +} diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Models/MicroserviceResult.cs b/samples/OcelotServiceDiscovery/DownstreamService/Models/MicroserviceResult.cs new file mode 100644 index 000000000..0da25223b --- /dev/null +++ b/samples/OcelotServiceDiscovery/DownstreamService/Models/MicroserviceResult.cs @@ -0,0 +1,6 @@ +namespace Ocelot.Samples.ServiceDiscovery.DownstreamService.Models; + +public class MicroserviceResult +{ + public Uri Next { get; set; } +} diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Models/ReadyResult.cs b/samples/OcelotServiceDiscovery/DownstreamService/Models/ReadyResult.cs new file mode 100644 index 000000000..040a3c2ad --- /dev/null +++ b/samples/OcelotServiceDiscovery/DownstreamService/Models/ReadyResult.cs @@ -0,0 +1,10 @@ +using System; + +namespace Ocelot.Samples.ServiceDiscovery.DownstreamService.Models; + +public class ReadyResult : MicroserviceResult +{ + public string ServiceName { get; set; } + public string ServiceVersion { get; set; } + public DateTime StartedAt { get; set; } +} diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Models/WeatherForecast.cs b/samples/OcelotServiceDiscovery/DownstreamService/Models/WeatherForecast.cs new file mode 100644 index 000000000..16be49cba --- /dev/null +++ b/samples/OcelotServiceDiscovery/DownstreamService/Models/WeatherForecast.cs @@ -0,0 +1,12 @@ +namespace Ocelot.Samples.ServiceDiscovery.DownstreamService.Models; + +public class WeatherForecast +{ + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } +} diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj b/samples/OcelotServiceDiscovery/DownstreamService/Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj index aee1bfae0..b7c731bea 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj +++ b/samples/OcelotServiceDiscovery/DownstreamService/Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj @@ -1,10 +1,17 @@ - + net7.0 + disable + enable + Linux + . + d5492aa8-b50c-41ae-a044-9954846db9ac + + diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Program.cs b/samples/OcelotServiceDiscovery/DownstreamService/Program.cs index 068f24a1f..2cfe402d1 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Program.cs +++ b/samples/OcelotServiceDiscovery/DownstreamService/Program.cs @@ -1,6 +1,7 @@ -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using System; +global using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore; + +[assembly: ApiController] namespace Ocelot.Samples.ServiceDiscovery.DownstreamService; @@ -8,11 +9,9 @@ public class Program { public static void Main(string[] args) { - BuildWebHost(args).Run(); - } - - public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup() - .Build(); + .Build() + .Run(); + } } diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Properties/launchSettings.json b/samples/OcelotServiceDiscovery/DownstreamService/Properties/launchSettings.json index 261fa52ec..a6ccfad22 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Properties/launchSettings.json +++ b/samples/OcelotServiceDiscovery/DownstreamService/Properties/launchSettings.json @@ -1,29 +1,48 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:53908/", - "sslPort": 0 - } - }, "profiles": { - "IIS Express": { - "commandName": "IISExpress", + "http": { + "commandName": "Project", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - } + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5001" }, - "DownstreamService": { + "https": { "commandName": "Project", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "applicationUrl": "http://localhost:5001/" + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7001;http://localhost:5001" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Docker": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "publishAllPorts": true, + "useSSL": true + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:65100", + "sslPort": 44373 } } } diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Startup.cs b/samples/OcelotServiceDiscovery/DownstreamService/Startup.cs index b541e186d..e605c7ba3 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Startup.cs +++ b/samples/OcelotServiceDiscovery/DownstreamService/Startup.cs @@ -1,9 +1,4 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using System.Text.Json; +using System.Text.Json; using System.Text.Json.Serialization; namespace Ocelot.Samples.ServiceDiscovery.DownstreamService; @@ -43,9 +38,13 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { - app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(); + app.UseDeveloperExceptionPage(); + } + else + { + app.UseHttpsRedirection(); } app.UseRouting(); diff --git a/samples/OcelotServiceDiscovery/DownstreamService/appsettings.Development.json b/samples/OcelotServiceDiscovery/DownstreamService/appsettings.Development.json index fa8ce71a9..b0bacf428 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/appsettings.Development.json +++ b/samples/OcelotServiceDiscovery/DownstreamService/appsettings.Development.json @@ -1,10 +1,8 @@ { "Logging": { - "IncludeScopes": false, "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" + "Default": "Information", + "Microsoft.AspNetCore": "Warning" } } } diff --git a/samples/OcelotServiceDiscovery/DownstreamService/appsettings.json b/samples/OcelotServiceDiscovery/DownstreamService/appsettings.json index cc7d4c2a6..223027717 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/appsettings.json +++ b/samples/OcelotServiceDiscovery/DownstreamService/appsettings.json @@ -1,8 +1,9 @@ { "Logging": { - "IncludeScopes": false, - "LogLevel": { "Default": "Warning" } + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } }, - "Urls": "http://localhost:5001" + "AllowedHosts": "*" } - From a5aa5d2f3c457b1924771c1affbff299b47ecc2e Mon Sep 17 00:00:00 2001 From: raman-m Date: Wed, 21 Jun 2023 21:00:10 +0300 Subject: [PATCH 19/27] Correct registration of IServiceDiscoveryProviderFactory interface --- samples/OcelotServiceDiscovery/.dockerignore | 2 +- samples/OcelotServiceDiscovery/ApiGateway/Program.cs | 10 +++++++--- .../DownstreamService/.dockerignore | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/samples/OcelotServiceDiscovery/.dockerignore b/samples/OcelotServiceDiscovery/.dockerignore index 3729ff0cd..e7b690f11 100644 --- a/samples/OcelotServiceDiscovery/.dockerignore +++ b/samples/OcelotServiceDiscovery/.dockerignore @@ -22,4 +22,4 @@ **/secrets.dev.yaml **/values.dev.yaml LICENSE -README.md \ No newline at end of file +README.md diff --git a/samples/OcelotServiceDiscovery/ApiGateway/Program.cs b/samples/OcelotServiceDiscovery/ApiGateway/Program.cs index e9aef24f4..796a5788b 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/Program.cs +++ b/samples/OcelotServiceDiscovery/ApiGateway/Program.cs @@ -2,10 +2,10 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Ocelot.DependencyInjection; using Ocelot.Middleware; using Ocelot.ServiceDiscovery; -using Ocelot.ServiceDiscovery.Providers; namespace Ocelot.Samples.ServiceDiscovery.ApiGateway; @@ -45,8 +45,12 @@ public static IWebHost BuildWebHost(string[] args) => { // Option #2. Abstract from default factory (ServiceDiscoveryProviderFactory) and from FinderDelegate, // and build custom factory by implementation of the IServiceDiscoveryProviderFactory interface. - s.AddScoped(); - s.AddScoped(); + s.RemoveAll(); + s.AddSingleton(); + + // Will not be called, but it is required for internal validators, aka life hack + s.AddSingleton((serviceProvider, config, downstreamRoute) + => null); // => new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute)); } s.AddOcelot(); diff --git a/samples/OcelotServiceDiscovery/DownstreamService/.dockerignore b/samples/OcelotServiceDiscovery/DownstreamService/.dockerignore index 3729ff0cd..e7b690f11 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/.dockerignore +++ b/samples/OcelotServiceDiscovery/DownstreamService/.dockerignore @@ -22,4 +22,4 @@ **/secrets.dev.yaml **/values.dev.yaml LICENSE -README.md \ No newline at end of file +README.md From 909a124813bb36ac870fb27e5c9a5409424e5845 Mon Sep 17 00:00:00 2001 From: Raman Maksimchuk Date: Wed, 21 Jun 2023 18:47:43 +0300 Subject: [PATCH 20/27] Update README.md: Fix upstream path because of case sensitivity --- samples/OcelotServiceDiscovery/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/OcelotServiceDiscovery/README.md b/samples/OcelotServiceDiscovery/README.md index 49f14a2a3..40fd42a8d 100644 --- a/samples/OcelotServiceDiscovery/README.md +++ b/samples/OcelotServiceDiscovery/README.md @@ -21,7 +21,7 @@ dotnet run Leave the gateway running. ### 3. Make a HTTP request -To the URL: http://localhost:5000/Categories
+To the URL: http://localhost:5000/categories
You should get the following response: ```json { From 5624ed5a4a67997be395ced1abbfc859d3887349 Mon Sep 17 00:00:00 2001 From: Raman Maksimchuk Date: Wed, 21 Jun 2023 19:13:31 +0300 Subject: [PATCH 21/27] Update servicediscovery.rst: Update Custom Providers section. Add sample solution. --- docs/features/servicediscovery.rst | 84 +++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/docs/features/servicediscovery.rst b/docs/features/servicediscovery.rst index d52763fa4..7548165f7 100644 --- a/docs/features/servicediscovery.rst +++ b/docs/features/servicediscovery.rst @@ -7,11 +7,13 @@ Ocelot allows you to specify a service discovery provider and will use this to f GlobalConfiguration section which means the same service discovery provider will be used for all Routes you specify a ServiceName for at Route level. Consul -^^^^^^ +------ The first thing you need to do is install the NuGet package that provides Consul support in Ocelot. -``Install-Package Ocelot.Provider.Consul`` +.. code-block:: powershell + + Install-Package Ocelot.Provider.Consul Then add the following to your ConfigureServices method. @@ -92,7 +94,7 @@ Or } ACL Token ---------- +^^^^^^^^^ If you are using ACL with Consul Ocelot supports adding the X-Consul-Token header. In order so this to work you must add the additional property below. @@ -108,13 +110,15 @@ If you are using ACL with Consul Ocelot supports adding the X-Consul-Token heade Ocelot will add this token to the Consul client that it uses to make requests and that is then used for every request. Eureka -^^^^^^ +------ This feature was requested as part of `Issue 262 `_ . to add support for Netflix's Eureka service discovery provider. The main reason for this is it is a key part of `Steeltoe `_ which is something to do with `Pivotal `_! Anyway enough of the background. The first thing you need to do is install the NuGet package that provides Eureka support in Ocelot. -``Install-Package Ocelot.Provider.Eureka`` +.. code-block:: powershell + + Install-Package Ocelot.Provider.Eureka Then add the following to your ConfigureServices method. @@ -150,7 +154,7 @@ Ocelot will now register all the necessary services when it starts up and if you Ocelot will use the scheme (http/https) set in Eureka if these values are not provided in ocelot.json Dynamic Routing -^^^^^^^^^^^^^^^ +--------------- This feature was requested in `issue 340 `_. The idea is to enable dynamic routing when using a service discovery provider (see that section of the docs for more info). In this mode Ocelot will use the first segment of the upstream path to lookup the downstream service with the service discovery provider. @@ -244,7 +248,7 @@ This configuration means that if you have a request come into Ocelot on /product Please take a look through all of the docs to understand these options. Custom Providers -^^^^^^^^^^^^^^^^ +---------------------------------- Ocelot also allows you to create a custom ServiceDiscovery implementation. This is done by implementing the ``IServiceDiscoveryProvider`` interface like in the following example: @@ -289,4 +293,68 @@ Finally, in the application's **ConfigureServices** method register a ``ServiceD }; services.AddSingleton(serviceDiscoveryFinder); services.AddOcelot(); - + +Custom provider sample +^^^^^^^^^^^^^^^^^^^^^^ + +In order to introduce the basic template of custom Service Discovery provider we've prepared nice Web API sample: + + | **Link**: `samples <../../samples>`_ / `OcelotServiceDiscovery <../../samples/OcelotServiceDiscovery>`_ + | **Solution**: `Ocelot.Samples.ServiceDiscovery.sln <../../samples/OcelotServiceDiscovery/Ocelot.Samples.ServiceDiscovery.sln>`_ + +This solution contains the following projects: + +- `ApiGateway <#apigateway>`_ +- `DownstreamService <#downstreamservice>`_ + +This solution is ready for any kind of deployment. All services are linked which means all ports and hosts are prepared for immediate usage (running in Visual Studio). + +All instructions for running this solution are in `README.md <../../samples/OcelotServiceDiscovery/README.md>`_. + +DownstreamService +""""""""""""""""" + +This project is a single downstream service to be reused in `ApiGateway <#apigateway>`_ routes. +It has multiple **launchSettings.json** profiles for your favorite startup and hosting scenarios: in Visual Studio running sessions, console Kestrel hosting and Docker deployment for sure. + +ApiGateway +"""""""""" + +This project includes custom Service Discovery provider, and it has a route(s) to `DownstreamService <#downstreamservice>`_ services only in **ocelot.json** file. +You are welcome to add more routes! + +The main source code for the custom provider is in the `ServiceDiscovery <../../samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery>`_ folder: +the ``MyServiceDiscoveryProvider`` and ``MyServiceDiscoveryProviderFactory`` classes. You are welcome to design and develop them! + +Also, the keystone of this custom provider locates in ``ConfigureServices`` method where you could choose a design & implementation options: easy or more complex: + +.. code-block:: csharp + + builder.ConfigureServices(s => + { + // Initialize from app configuration or hardcode/choose the best option. + bool easyWay = true; + + if (easyWay) + { + // Option #1. Define custom finder delegate to instantiate custom provider + // by default factory which is ServiceDiscoveryProviderFactory + s.AddSingleton((serviceProvider, config, downstreamRoute) + => new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute)); + } + else + { + // Option #2. Abstract from default factory (ServiceDiscoveryProviderFactory) and from FinderDelegate, + // and build custom factory by implementation of the IServiceDiscoveryProviderFactory interface. + s.AddScoped(); + s.AddScoped(); + } + + s.AddOcelot(); + }); + +Easy way, simple design means you develop provider class only and specify ``ServiceDiscoveryFinderDelegate`` object for default ``ServiceDiscoveryProviderFactory`` in Ocelot core. + +More complex design means you develop both, provider and provider's factory classes. After that you need to add both the ``IServiceDiscoveryProvider`` and ``IServiceDiscoveryProviderFactory`` +interfaces to DI-container. Please note, in this case default ``ServiceDiscoveryProviderFactory`` in Ocelot core will not be used. +Additionally you don't have to specify ``"Type": "MyServiceDiscoveryProvider"`` in the **ServiceDiscoveryProvider** options of the GlobalConfiguration settings. From 93a8cd3cb4627b4f038bb6dd3bdbd1b3aec5dd8e Mon Sep 17 00:00:00 2001 From: Raman Maksimchuk Date: Wed, 21 Jun 2023 21:15:10 +0300 Subject: [PATCH 22/27] Update servicediscovery.rst: Update actual code from the sample --- docs/features/servicediscovery.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/features/servicediscovery.rst b/docs/features/servicediscovery.rst index 7548165f7..df65ae470 100644 --- a/docs/features/servicediscovery.rst +++ b/docs/features/servicediscovery.rst @@ -346,8 +346,11 @@ Also, the keystone of this custom provider locates in ``ConfigureServices`` meth { // Option #2. Abstract from default factory (ServiceDiscoveryProviderFactory) and from FinderDelegate, // and build custom factory by implementation of the IServiceDiscoveryProviderFactory interface. - s.AddScoped(); - s.AddScoped(); + s.RemoveAll(); + s.AddSingleton(); + + // Will not be called, but it is required for internal validators, aka life hack + s.AddSingleton((serviceProvider, config, downstreamRoute) => null); } s.AddOcelot(); @@ -355,6 +358,8 @@ Also, the keystone of this custom provider locates in ``ConfigureServices`` meth Easy way, simple design means you develop provider class only and specify ``ServiceDiscoveryFinderDelegate`` object for default ``ServiceDiscoveryProviderFactory`` in Ocelot core. -More complex design means you develop both, provider and provider's factory classes. After that you need to add both the ``IServiceDiscoveryProvider`` and ``IServiceDiscoveryProviderFactory`` -interfaces to DI-container. Please note, in this case default ``ServiceDiscoveryProviderFactory`` in Ocelot core will not be used. +More complex design means you develop both, provider and provider's factory classes. After that you need to add the ``IServiceDiscoveryProviderFactory`` +interface to DI-container with removal of registered default ``ServiceDiscoveryProviderFactory`` class. +Please note, in this case default ``ServiceDiscoveryProviderFactory`` in Ocelot core will not be used. Additionally you don't have to specify ``"Type": "MyServiceDiscoveryProvider"`` in the **ServiceDiscoveryProvider** options of the GlobalConfiguration settings. +But you can leave this ``Type`` option for compatibility between both designs. From 084892787ddc0837734db2d0c52d4f3342a1ca4e Mon Sep 17 00:00:00 2001 From: raman-m Date: Wed, 21 Jun 2023 21:19:52 +0300 Subject: [PATCH 23/27] Remove obsolete code --- samples/OcelotServiceDiscovery/ApiGateway/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/OcelotServiceDiscovery/ApiGateway/Program.cs b/samples/OcelotServiceDiscovery/ApiGateway/Program.cs index 796a5788b..1a0e37336 100644 --- a/samples/OcelotServiceDiscovery/ApiGateway/Program.cs +++ b/samples/OcelotServiceDiscovery/ApiGateway/Program.cs @@ -50,7 +50,7 @@ public static IWebHost BuildWebHost(string[] args) => // Will not be called, but it is required for internal validators, aka life hack s.AddSingleton((serviceProvider, config, downstreamRoute) - => null); // => new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute)); + => null); } s.AddOcelot(); From 009185725d7f26fa1728ed3ddd4f729ff2f6eb6e Mon Sep 17 00:00:00 2001 From: raman-m Date: Fri, 8 Sep 2023 16:28:26 +0300 Subject: [PATCH 24/27] CS8632 The annotation for nullable reference types should only be used in code within a '#nullable' annotations context --- .../DownstreamService/Models/WeatherForecast.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/OcelotServiceDiscovery/DownstreamService/Models/WeatherForecast.cs b/samples/OcelotServiceDiscovery/DownstreamService/Models/WeatherForecast.cs index 16be49cba..06622a9ec 100644 --- a/samples/OcelotServiceDiscovery/DownstreamService/Models/WeatherForecast.cs +++ b/samples/OcelotServiceDiscovery/DownstreamService/Models/WeatherForecast.cs @@ -8,5 +8,5 @@ public class WeatherForecast public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - public string? Summary { get; set; } + public string Summary { get; set; } } From afd495f94d434ccb0f0d7710da03a65c547098df Mon Sep 17 00:00:00 2001 From: raman-m Date: Fri, 8 Sep 2023 17:06:46 +0300 Subject: [PATCH 25/27] Revert to previous state --- .../ServiceDiscoveryProviderFactory.cs | 109 +++++++++--------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs index ed2324460..64ea07d2c 100644 --- a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs +++ b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs @@ -8,58 +8,59 @@ using System; using System.Collections.Generic; -namespace Ocelot.ServiceDiscovery; - -public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory -{ - private readonly IOcelotLoggerFactory _factory; - private readonly ServiceDiscoveryFinderDelegate _delegates; - private readonly IServiceProvider _provider; - - public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IServiceProvider provider) - { - _factory = factory; - _provider = provider; - _delegates = provider.GetService(); - } - - public Response Get(ServiceProviderConfiguration serviceConfig, DownstreamRoute route) - { - if (route.UseServiceDiscovery) - { - return GetServiceDiscoveryProvider(serviceConfig, route); - } - - var services = new List(); - - foreach (var downstreamAddress in route.DownstreamAddresses) - { - var service = new Service(route.ServiceName, new ServiceHostAndPort(downstreamAddress.Host, downstreamAddress.Port, route.DownstreamScheme), string.Empty, string.Empty, Array.Empty()); - - services.Add(service); - } - - return new OkResponse(new ConfigurationServiceProvider(services)); - } - - private Response GetServiceDiscoveryProvider(ServiceProviderConfiguration config, DownstreamRoute route) - { - if (config.Type?.ToLower() == "servicefabric") - { - var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, route.ServiceName); - return new OkResponse(new ServiceFabricServiceDiscoveryProvider(sfConfig)); - } - - if (_delegates != null) - { - var provider = _delegates?.Invoke(_provider, config, route); - - if (provider.GetType().Name.ToLower() == config.Type.ToLower()) - { - return new OkResponse(provider); - } - } - - return new ErrorResponse(new UnableToFindServiceDiscoveryProviderError($"Unable to find service discovery provider for type: {config.Type}")); +namespace Ocelot.ServiceDiscovery +{ + public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory + { + private readonly IOcelotLoggerFactory _factory; + private readonly ServiceDiscoveryFinderDelegate _delegates; + private readonly IServiceProvider _provider; + + public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IServiceProvider provider) + { + _factory = factory; + _provider = provider; + _delegates = provider.GetService(); + } + + public Response Get(ServiceProviderConfiguration serviceConfig, DownstreamRoute route) + { + if (route.UseServiceDiscovery) + { + return GetServiceDiscoveryProvider(serviceConfig, route); + } + + var services = new List(); + + foreach (var downstreamAddress in route.DownstreamAddresses) + { + var service = new Service(route.ServiceName, new ServiceHostAndPort(downstreamAddress.Host, downstreamAddress.Port, route.DownstreamScheme), string.Empty, string.Empty, Array.Empty()); + + services.Add(service); + } + + return new OkResponse(new ConfigurationServiceProvider(services)); + } + + private Response GetServiceDiscoveryProvider(ServiceProviderConfiguration config, DownstreamRoute route) + { + if (config.Type?.ToLower() == "servicefabric") + { + var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, route.ServiceName); + return new OkResponse(new ServiceFabricServiceDiscoveryProvider(sfConfig)); + } + + if (_delegates != null) + { + var provider = _delegates?.Invoke(_provider, config, route); + + if (provider.GetType().Name.ToLower() == config.Type.ToLower()) + { + return new OkResponse(provider); + } + } + + return new ErrorResponse(new UnableToFindServiceDiscoveryProviderError($"Unable to find service discovery provider for type: {config.Type}")); + } } -} +} From 2127294fb64fb9b840b01bf2984984a71584be4d Mon Sep 17 00:00:00 2001 From: raman-m Date: Fri, 8 Sep 2023 17:15:01 +0300 Subject: [PATCH 26/27] Revert back to the version from ThreeMammals:develop --- .../ServiceDiscoveryProviderFactory.cs | 119 +++++++++--------- 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs index 64ea07d2c..ed04c3532 100644 --- a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs +++ b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs @@ -1,66 +1,73 @@ -using Microsoft.Extensions.DependencyInjection; -using Ocelot.Configuration; -using Ocelot.Logging; -using Ocelot.Responses; -using Ocelot.ServiceDiscovery.Configuration; -using Ocelot.ServiceDiscovery.Providers; -using Ocelot.Values; using System; using System.Collections.Generic; - -namespace Ocelot.ServiceDiscovery -{ - public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory - { - private readonly IOcelotLoggerFactory _factory; - private readonly ServiceDiscoveryFinderDelegate _delegates; - private readonly IServiceProvider _provider; - public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IServiceProvider provider) - { - _factory = factory; - _provider = provider; - _delegates = provider.GetService(); - } - - public Response Get(ServiceProviderConfiguration serviceConfig, DownstreamRoute route) - { - if (route.UseServiceDiscovery) - { - return GetServiceDiscoveryProvider(serviceConfig, route); - } - - var services = new List(); - - foreach (var downstreamAddress in route.DownstreamAddresses) - { - var service = new Service(route.ServiceName, new ServiceHostAndPort(downstreamAddress.Host, downstreamAddress.Port, route.DownstreamScheme), string.Empty, string.Empty, Array.Empty()); +using Ocelot.ServiceDiscovery.Configuration; - services.Add(service); - } +using Ocelot.Logging; - return new OkResponse(new ConfigurationServiceProvider(services)); - } +using Microsoft.Extensions.DependencyInjection; - private Response GetServiceDiscoveryProvider(ServiceProviderConfiguration config, DownstreamRoute route) - { - if (config.Type?.ToLower() == "servicefabric") - { - var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, route.ServiceName); - return new OkResponse(new ServiceFabricServiceDiscoveryProvider(sfConfig)); - } +using Ocelot.Configuration; - if (_delegates != null) - { - var provider = _delegates?.Invoke(_provider, config, route); +using Ocelot.ServiceDiscovery.Providers; - if (provider.GetType().Name.ToLower() == config.Type.ToLower()) - { - return new OkResponse(provider); - } - } +using Ocelot.Responses; - return new ErrorResponse(new UnableToFindServiceDiscoveryProviderError($"Unable to find service discovery provider for type: {config.Type}")); - } +using Ocelot.Values; + +namespace Ocelot.ServiceDiscovery +{ + public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory + { + private readonly IOcelotLoggerFactory _factory; + private readonly ServiceDiscoveryFinderDelegate _delegates; + private readonly IServiceProvider _provider; + + public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IServiceProvider provider) + { + _factory = factory; + _provider = provider; + _delegates = provider.GetService(); + } + + public Response Get(ServiceProviderConfiguration serviceConfig, DownstreamRoute route) + { + if (route.UseServiceDiscovery) + { + return GetServiceDiscoveryProvider(serviceConfig, route); + } + + var services = new List(); + + foreach (var downstreamAddress in route.DownstreamAddresses) + { + var service = new Service(route.ServiceName, new ServiceHostAndPort(downstreamAddress.Host, downstreamAddress.Port, route.DownstreamScheme), string.Empty, string.Empty, Array.Empty()); + + services.Add(service); + } + + return new OkResponse(new ConfigurationServiceProvider(services)); + } + + private Response GetServiceDiscoveryProvider(ServiceProviderConfiguration config, DownstreamRoute route) + { + if (config.Type?.ToLower() == "servicefabric") + { + var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, route.ServiceName); + return new OkResponse(new ServiceFabricServiceDiscoveryProvider(sfConfig)); + } + + if (_delegates != null) + { + var provider = _delegates?.Invoke(_provider, config, route); + + if (provider.GetType().Name.ToLower() == config.Type.ToLower()) + { + return new OkResponse(provider); + } + } + + return new ErrorResponse(new UnableToFindServiceDiscoveryProviderError($"Unable to find service discovery provider for type: {config.Type}")); + } } -} +} From d14543bef2373b1e72f956cdd35bff79ad29082e Mon Sep 17 00:00:00 2001 From: Raman Maksimchuk Date: Thu, 21 Sep 2023 12:10:06 +0300 Subject: [PATCH 27/27] Update servicediscovery.rst: English checking --- docs/features/servicediscovery.rst | 43 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/docs/features/servicediscovery.rst b/docs/features/servicediscovery.rst index df65ae470..131889853 100644 --- a/docs/features/servicediscovery.rst +++ b/docs/features/servicediscovery.rst @@ -250,8 +250,8 @@ Please take a look through all of the docs to understand these options. Custom Providers ---------------------------------- -Ocelot also allows you to create a custom ServiceDiscovery implementation. -This is done by implementing the ``IServiceDiscoveryProvider`` interface like in the following example: +Ocelot also allows you to create your own ServiceDiscovery implementation. +This is done by implementing the ``IServiceDiscoveryProvider`` interface, as shown in the following example: .. code-block:: csharp @@ -283,7 +283,7 @@ And set its class name as the provider type in **ocelot.json**: } } -Finally, in the application's **ConfigureServices** method register a ``ServiceDiscoveryFinderDelegate`` to initialize and return the provider: +Finally, in the application's **ConfigureServices** method, register a ``ServiceDiscoveryFinderDelegate`` to initialize and return the provider: .. code-block:: csharp @@ -294,10 +294,10 @@ Finally, in the application's **ConfigureServices** method register a ``ServiceD services.AddSingleton(serviceDiscoveryFinder); services.AddOcelot(); -Custom provider sample +Custom Provider Sample ^^^^^^^^^^^^^^^^^^^^^^ -In order to introduce the basic template of custom Service Discovery provider we've prepared nice Web API sample: +In order to introduce a basic template for a custom Service Discovery provider, we've prepared a good sample: | **Link**: `samples <../../samples>`_ / `OcelotServiceDiscovery <../../samples/OcelotServiceDiscovery>`_ | **Solution**: `Ocelot.Samples.ServiceDiscovery.sln <../../samples/OcelotServiceDiscovery/Ocelot.Samples.ServiceDiscovery.sln>`_ @@ -307,59 +307,58 @@ This solution contains the following projects: - `ApiGateway <#apigateway>`_ - `DownstreamService <#downstreamservice>`_ -This solution is ready for any kind of deployment. All services are linked which means all ports and hosts are prepared for immediate usage (running in Visual Studio). +This solution is ready for any deployment. All services are bound, meaning all ports and hosts are prepared for immediate use (running in Visual Studio). All instructions for running this solution are in `README.md <../../samples/OcelotServiceDiscovery/README.md>`_. DownstreamService """"""""""""""""" -This project is a single downstream service to be reused in `ApiGateway <#apigateway>`_ routes. -It has multiple **launchSettings.json** profiles for your favorite startup and hosting scenarios: in Visual Studio running sessions, console Kestrel hosting and Docker deployment for sure. +This project provides a single downstream service that can be reused across `ApiGateway <#apigateway>`_ routes. +It has multiple **launchSettings.json** profiles for your favorite launch and hosting scenarios: Visual Studio running sessions, Kestrel console hosting, and Docker deployments. ApiGateway """""""""" -This project includes custom Service Discovery provider, and it has a route(s) to `DownstreamService <#downstreamservice>`_ services only in **ocelot.json** file. -You are welcome to add more routes! +This project includes a custom Service Discovery provider and it only has route(s) to `DownstreamService <#downstreamservice>`_ services in the **ocelot.json** file. +You can add more routes! The main source code for the custom provider is in the `ServiceDiscovery <../../samples/OcelotServiceDiscovery/ApiGateway/ServiceDiscovery>`_ folder: the ``MyServiceDiscoveryProvider`` and ``MyServiceDiscoveryProviderFactory`` classes. You are welcome to design and develop them! -Also, the keystone of this custom provider locates in ``ConfigureServices`` method where you could choose a design & implementation options: easy or more complex: +Additionally, the cornerstone of this custom provider is the ``ConfigureServices`` method, where you can choose design and implementation options: simple or more complex: .. code-block:: csharp builder.ConfigureServices(s => { - // Initialize from app configuration or hardcode/choose the best option. + // Perform initialization from application configuration or hardcode/choose the best option. bool easyWay = true; if (easyWay) { - // Option #1. Define custom finder delegate to instantiate custom provider - // by default factory which is ServiceDiscoveryProviderFactory + // Design #1. Define a custom finder delegate to instantiate a custom provider under the default factory, which is ServiceDiscoveryProviderFactory s.AddSingleton((serviceProvider, config, downstreamRoute) => new MyServiceDiscoveryProvider(serviceProvider, config, downstreamRoute)); } else { - // Option #2. Abstract from default factory (ServiceDiscoveryProviderFactory) and from FinderDelegate, - // and build custom factory by implementation of the IServiceDiscoveryProviderFactory interface. + // Design #2. Abstract from the default factory (ServiceDiscoveryProviderFactory) and from FinderDelegate, + // and create your own factory by implementing the IServiceDiscoveryProviderFactory interface. s.RemoveAll(); s.AddSingleton(); - // Will not be called, but it is required for internal validators, aka life hack + // It will not be called, but it is necessary for internal validators, it is also a lifehack s.AddSingleton((serviceProvider, config, downstreamRoute) => null); } s.AddOcelot(); }); -Easy way, simple design means you develop provider class only and specify ``ServiceDiscoveryFinderDelegate`` object for default ``ServiceDiscoveryProviderFactory`` in Ocelot core. +The easy way, lite design means that you only design the provider class, and specify ``ServiceDiscoveryFinderDelegate`` object for default ``ServiceDiscoveryProviderFactory`` in Ocelot core. -More complex design means you develop both, provider and provider's factory classes. After that you need to add the ``IServiceDiscoveryProviderFactory`` -interface to DI-container with removal of registered default ``ServiceDiscoveryProviderFactory`` class. -Please note, in this case default ``ServiceDiscoveryProviderFactory`` in Ocelot core will not be used. -Additionally you don't have to specify ``"Type": "MyServiceDiscoveryProvider"`` in the **ServiceDiscoveryProvider** options of the GlobalConfiguration settings. +A more complex design means that you design both provider and provider factory classes. +After this, you need to add the ``IServiceDiscoveryProviderFactory`` interface to the DI-container, removing the default registered ``ServiceDiscoveryProviderFactory`` class. +Note that in this case the Ocelot core will not use ``ServiceDiscoveryProviderFactory`` by default. +Additionally, you do not need to specify ``"Type": "MyServiceDiscoveryProvider"`` in the **ServiceDiscoveryProvider** properties of the **GlobalConfiguration** settings. But you can leave this ``Type`` option for compatibility between both designs.