API Gateway Ocelot .Net Core 6.1 Setup - asp.net-core

The .Net 6 have removed the Start up Class and i am not able to find out how to configure Ocelot in new .Net 6 structure. I have found two methos
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddOcelot()// 1.ocelot.json goes where?
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddOcelot(); // 2.what is the use of this
Let me know Please

Add json file called ocelot.json in your project.
Then do configure like this in Program.cs:
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("ocelot.json")
.Build();
var builder = WebApplication.CreateBuilder(args);
//.....
builder.Services.AddOcelot(configuration);
var app = builder.Build();
//........
app.UseOcelot();
//......

You probably already have solved this, so this is meant for all the other developers looking for a solution to this. Below are two ways of adding the Ocelot configuration.
Add a new JSON file in your project named ocelot.json and add your configuration for ocelot inside.
The file ocelot.json has to be registered in Program.cs in order for Ocelot to load the configuration for your API Gateway.
Below are two examples of how you can register your Ocelot configuration.
1. Adding Ocelot configuration without environment check
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("ocelot.json")
.Build();
builder.Services.AddOcelot(configuration);
var app = builder.Build();
await app.UseOcelot();
app.MapGet("/", () => "Hello World!");
app.Run();
As you can see we load the configuration from ocelot.json by using .ConfigurationBuilder(). We then parse the configuration to the method for adding Ocelot to the service container before registering it's middleware.
2. Add Ocelot configuration for the current environment
I tend to have multiple environments for production, testing, local development, etc... instead of re-writing/updating the configuration loader with the specific configuration file for Ocelot, we can do it by checking what environment we are running.
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile($"ocelot.{builder.Environment.EnvironmentName}.json", true, true)
.Build();
builder.Services.AddOcelot(configuration);
var app = builder.Build();
await app.UseOcelot();
app.MapGet("/", () => "Hello World!");
app.Run();
In the code above we use IHostEnvironment to get the current environment name. We can then use string interpolation to dynamically insert the environment name into the string of our ocelot configuration file.
For this to work, you would have to add a new configuration file for each environment like this:
ocelot.json
├─ ocelot.Development.json
├─ ocelot.Local.json
├─ ocelot.Test.json

You need to declare direct from your program.cs you add your Ocelot json file in bulder.configuration, than in services add the Ocelot reference, and in the end start the intance app.Ocelot().wait();
Here is an example, hope it helps
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("ocelot.json");
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddOcelot();
var app = builder.Build();
//if (app.Environment.IsDevelopment())
//{
app.UseSwagger();
app.UseSwaggerUI();
//}
app.UseHttpsRedirection();
app.UseOcelot().Wait();
app.UseAuthorization();
app.MapControllers();
app.Run();

Related

swagger/index.html shows a blank page (asp.net core)

I am writing a web api in ASP.NET CORE for the data models Package and Content. They are originally from MSSQL so I connected to the db server successfully. After writing http requests in the controllers, when I ran the project to test, it takes me to swagger/index.html that shows a blank page, I have no idea why.
Here is my program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
//OperationsContext is a db context that has both content and package dbcontext
builder.Services.AddDbContext<OperationsContext>(x => x.UseSqlServer(connectionString));
/*builder.Services.AddMvc();
builder.Services.AddHttpContextAccessor();*/
builder.Services.AddScoped<IContentRepository, ContentRepository>();
builder.Services.AddScoped<IPackageRepository, PackageRepository>();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI(c =>
{
if (app.Environment.IsDevelopment() || app.Environment.IsProduction())
{
c.SwaggerEndpoint("/swagger/Package/swagger.json", "Package v1");
}
else
{
// To deploy on IIS
c.SwaggerEndpoint("/swagger/Package/swagger.json", "Package v1");
}
});
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
I am assuming it's the program.cs, but there are no issues when I ran it. Does anyone know why?
Swagger UI does not support Internet Explorer. Use Chrome, Firefox, Safari, or Edge instead.

Integration Testing Minimal API .NET 6 - nUnit

With .NET 5 I used the following in my nUnit [SetUp] for each test. This created a host and a client with which I could call my API with full integrations as defined in the Startup:
Microsoft.AspNetCore.TestHost.TestServer _testServer;
HttpClient _testClient;
[SetUp]
public async Task SetUp()
{
// Load up test configuration
IConfiguration config = new ConfigurationBuilder()
.SetBasePath("mypath")
.AddJsonFile("integrationsettings.json")
.Build();
// Create the host (using startup)
WebHostBuilder builder = new WebHostBuilder()
// Use startup from WebApp Server project
.UserStartup<MyWebApp.Startup>()
// Configure logging from integrationsettings.json
.ConfigureLogging((hostingContext, logging) =>
logging.AddConfiguration(config.GetSection("Logging"))
// Set core app configuration to use integrationsettings.json
.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(config))
// Add any additional services not loaded by startup
.ConfigureServices(services => // add additional services not laoded in Startup);
// Create the Server
_testServer = new TestServer(builder);
// Create the Client
_testClient = _testServer.CreateClient();
}
I could then use testClient HttpClient to work directly with my API.
Life was sweet.
I know I could still use the old model with .NET 6 (Program.cs + Startup.cs), but if I'm going to go with the flow, now that we have minimal API with just the Program.cs, how do I replicate the above?
From what I can gather, it looks like WebApplicationFactory is the key, but have not found anything that gets me over the line.
Is it as simple as adding the assembly that contains WebApplication and just build the app in test SetUp in the same way as I do in Program.cs on the server?
Is there a way to encapsulate the build logic (much like the old Startup.cs) so I do not need to duplicate the configuration used on the server in my tests?

Migration to Minimal API - Test Settings Json not overriding Program

Thanks to this answer: Integration test and hosting ASP.NET Core 6.0 without Startup class
I have been able to perform integration tests with API.
WebApplicationFactory<Program>? app = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
});
});
HttpClient? client = app.CreateClient();
This has worked using the appsettings.json from the API project. Am now trying to use integrationtestsettings.json instead using:
IConfiguration configuration = new ConfigurationBuilder()
.SetBasePath(ProjectDirectoryLocator.GetProjectDirectory())
.AddJsonFile("integrationtestsettings.json")
.Build();
WebApplicationFactory<Program>? app = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(configuration));
builder.ConfigureServices(services =>
{
});
});
_httpClient = app.CreateClient();
I have inspected the configuration variable and can see the properties loaded from my integrartiontestsettings.json file. However, the host is still running using the appsettings.json from the server project.
Previously, in .Net5, I was using WebHostBuilder and the settings were overridden by test settings.
WebHostBuilder webHostBuilder = new();
webHostBuilder.UseStartup<Startup>();
webHostBuilder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(_configuration));
But cannot get the test settings to apply using the WebApplicationFactory.
It seems the method has changed.
Changing:
builder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(configuration));
To:
builder.UseConfiguraton(configuration);
has done the trick.
builder.ConfigureAppConfiguration, now it's configuring the app (after your WebApplicationBuilder.Build() is called) and your WebApplication is created.
You need to "inject" your configurations before the .Build() is done. This is why you need to call UseConfiguraton instead of ConfigureAppConfiguration.

Configure logging via config file in .NET Core

We are trying to configure logging for our ASP.NET Core application via a configuration file (the default appsettings.json). The docu says it should be possible (https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1), but we can't get it working like expected.
What we have tried so far:
leave the code as it is in the project template for ASP.NET Core and just change the appsettings.json => no effect
explicitly add appsettings.json as config file and configure logging in Program.cs => no logging at all
public static IHostBuilder CreateHostBuilder (string[] args) =>
Host.CreateDefaultBuilder (args)
.ConfigureAppConfiguration ((hostingContext, config) =>
{
config.Sources.Clear ();
var env = hostingContext.HostingEnvironment;
config.AddJsonFile ("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile ($"appsettings.{env.EnvironmentName}.json",
optional: true, reloadOnChange: true);
config.AddEnvironmentVariables ();
})
.ConfigureLogging ((hostingContext, logging) =>
{
logging.ClearProviders ();
logging.AddConfiguration (hostingContext.Configuration.GetSection ("Logging"));
})
.ConfigureWebHostDefaults (webBuilder =>
{
webBuilder.UseStartup<Startup> ();
});
... configure logging in Startup.ConfigureServices => no effect
public void ConfigureServices (IServiceCollection services)
{
services.AddLogging (config => config.AddConfiguration (Configuration.GetSection("Logging")));
services.AddControllers ();
}
You misunderstood. You can configure logging, i.e. log levels for each provider, filtering out messages, etc., but the actual providers must be assigned in code. In other words, you can configure what messages go to the console via config, but you must still call logging.AddConsole() within ConfigureLogging to add that provider.
The code you have clears all the default providers and adds nothing, so there's no providers at all and hence no logs are generated. You cannot actually add the providers via config, just configure providers that have been added.

How do we set ContentRootPath and WebRootPath?

We're ending up with the following ContentRoot and WebRoot when we run our app from IIS.
ContentRoot: C:\MyApp\wwwroot
WebRoot: C:\MyApp\wwwroot\wwwroot
Here is how we are setting ContentRoot and WebRoot.
public class Startup
{
private readonly IHostingEnvironment _hostingEnv;
public Startup(IHostingEnvironment hostingEnv)
{
_hostingEnv = hostingEnv;
}
public void Configure(IApplicationBuilder app)
{
app.Run(context =>
{
// test output
context.Response.WriteAsync(_hostingEnv.ContentRootPath + "\r\n");
return context.Response.WriteAsync(_hostingEnv.WebRootPath + "\r\n");
});
}
public static void Main(string[] args)
{
var contentRoot = Directory.GetCurrentDirectory();
var webRoot = Path.Combine(contentRoot, "wwwroot");
var host = new WebHostBuilder()
.UseKestrel()
.UseIISPlatformHandlerUrl()
.UseContentRoot(contentRoot) // set content root
.UseWebRoot(webRoot) // set web root
.UseStartup<Startup>()
.Build();
host.Run();
}
}
From intellisense I see that...
ContentRootPath contains the application content files.
WebRootPath contains the web-servable content files.
How do we make the test output look instead like this:
ContentRoot: C:\MyApp\
WebRoot: C:\MyApp\wwwroot\
While RC2 documentation is still being prepared, here is what I learned while trying to deploy pre-RC2 app as Azure Web App:
There is no Visual Studio tooling yet, so the app must be published and deployed manually over FTP. For publishing, use: dotnet publish --configuration Release --output ./approot
If connected to Azure over FTP, you will probably see something similar to:
The "approot" folder can be replaced with the published one (the web.config is left in the approot).
The "approot" must be configured as a virtual application in Azure Portal (the default was site\wwwroot):
An the last thing to get static files served from the wwwroot folder, the Startup.cs file should be modified to include custom UseWebRoot call:
var currentDirectory = Directory.GetCurrentDirectory();
var host = new WebHostBuilder()
.UseKestrel()
.UseWebRoot(Path.Combine(currentDirectory, "..", "wwwroot"))
.UseDefaultHostingConfiguration(args)
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
After these steps you should have ASPNET Core pre-RC2 web app running on Azure.
In RC2, if we put the web.config beside wwwroot and point IIS at the MyApp directory like this...
MyApp
web.config
wwwroot
...the code from the original question outputs this...
ContentRoot: C:\MyApp\
WebRoot: C:\MyApp\wwwroot\