Branching OWIN pipeline based on hostname - c#

With OWIN (specifically Katana) it is possible to configure applications to different branches. For example:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/branch1", branch1 => branch1.UseMiddlewareA());
app.Map("/branch2", branch2 => branch2.UseMiddlewareB());
app.UseDefaultMiddleware();
}
}
Is it possible to achieve the same thing based on host name rather than route path? So for exampl, say you have www.mydomain.com/blog configured with app.Map("/blog", blog => blog.UseBlog()); Instead of this, you want to use blog.mydomain.com. Both blog.mydomain.com and www.mydomain.com point to the same web application, but for the blog sub-domain, I want it to use a different app configuration within the OWIN pipeline.
Many thanks for any help.

Yes, you can do this with MapWhen.
http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin/Mapping/MapWhenExtensions.cs

Related

"Microsoft.Extensions.DependencyInjection" and different concretes per environment

"Microsoft.Extensions.DependencyInjection"
List of "environments"
Production
Uat
Qa
DevShared
LocalDev
With DotNet (Framework/Classic) 4.6 or above (aka, "in the past", I used "Unity" with xml configuration. https://blogs.msdn.microsoft.com/miah/2009/04/03/testing-your-unity-xml-configuration/
(In the past before Dot Net core when using "Unity" IoC/DI)...When I had a need to have a concrete specific to an environment, I would tweak the concrete on the .xml.
For instance, let's say my webApi needed authentication in production, uat, qa and dev-shared. but in dev-local, I do not want to deal with authentication all the time as I developed the webApi, I would have 2 concretes.
IAuthorizer
MyRealAuthorizer : IAuthorizer
MyDevLetEverythingThroughAuthorizer : IAuthorizer
and I would "register" one of them .. using xml.
My build process would alter the unity.xml (unity.config to be precise) and change out (via xml-update-tasks in msbuild)
MyDevLetEverythingThroughAuthorizer
to
MyRealAuthorizer
.
.....
Java Spring has "annotation" based:
import org.springframework.context.annotation.Profile;
#Profile("localdev")
public class MyDevLetEverythingThroughAuthorizer implements IAuthorizer {
#Profile("!localdev")
public class MyRealAuthorizer implements IAuthorizer {
But that does not honor the "Composite Root" pattern : (Mark Seeman http://blog.ploeh.dk/2011/07/28/CompositionRoot/ )
.......
So now I'm entering the world of DotNetCore. Everything has been going smooth. But I finally hit a situation where I need a dev-friendly concrete vs a non-dev "real" concretes.
Xml isn't available (to my best knowledge) with "Microsoft.Extensions.DependencyInjection".
I'm not sure of the best practice with DotNetCore in this situation.
I would prefer to honor the Composite Root pattern.
Basically, the below......but respecting the environments.
asp.net'ish
public void ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
/* need this for "local-dev" */
services.AddScoped<IAuthorizer, MyDevLetEverythingThroughAuthorizer>();
/* need this for everything EXCEPT "local-dev" */
services.AddScoped<IAuthorizer, MyRealAuthorizer>();
}
(not asp.net) dot.net core'ish too
private static System.IServiceProvider BuildDi()
{
//setup our DI
IServiceProvider serviceProvider = new ServiceCollection()
.AddLogging()
/* need this for "local-dev" */
.AddSingleton<IAuthorizer, MyDevLetEverythingThroughAuthorizer>()
/* need this for everything EXCEPT "local-dev" */
.AddSingleton<IAuthorizer, MyRealAuthorizer>()
APPEND
This article and snipplet help me understand the "what is built in" portion a little better:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-2.2
Environments ASP.NET Core reads the environment variable
ASPNETCORE_ENVIRONMENT at app startup and stores the value in
IHostingEnvironment.EnvironmentName. You can set
ASPNETCORE_ENVIRONMENT to any value, but three values are supported by
the framework: Development, Staging, and Production. If
ASPNETCORE_ENVIRONMENT isn't set, it defaults to Production.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
if (env.IsProduction() || env.IsStaging() || env.IsEnvironment("Staging_2"))
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
}
The
env.IsEnvironment("Staging_2") (akin to env.IsEnvironment("MyCustomValue") ) is the trick I guess.
APPEND:
This SOF question made it more clear for Asp.Net Core.
How to set aspnetcore_environment in publish file?
And ways you can set the environment variable without actually setting a (machine) environment variable!
public void ConfigureServices(IServiceCollection services, IHostingEnvironment environment) {
if (environment.IsDevelopment()) {
// bla bla bla
} else {
// bla bla bla
}
// register no-matter-which-environment services
}
Your question seems to be talking about two things: setting configuration from XML files and managing services using IServiceCollection. For .net core web applications, these happen in two stages:
A key value pair is consolidated from various pre-defined and custom sources (including json, XML, environment). All preset .net core web templates do this in program.cs.
The key value pair collection is sent to the Startup class that can be accessed via DI from the IConfiguration variable. Check this link for more information.
With this being the process, all config files are added before the ConfigureServices method is called in the Startup class. If you would like to add XML files to this configuration, you can set the following code in your program.cs:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
// additional code
.UseConfiguration(
new ConfigurationBuilder()
.AddXmlFile("file.xml", true) // second param is if file is optional
.Build()
)
// end of additional code
.UseStartup<Startup>();
If you want to access your environment, if they are set as environment variables, you can use one of the Environment.Get... functions.
Regarding your service, I am not sure in what way you are trying to access your XML, but you can always inject the IConfiguration as the simplest solution if you need to. However, I would advise against exposing your entire configuration to your services and have a look at setting up options with the help of this documentation

Is it possible to use arbitrary middleware in specific controller or ever method in asp.net web api2?

I have a bunch of already written middlewares. As i know they can easily be used at global pipeline level.
[assembly: OwinStartup(typeof(Startup))]
namespace Portal.Web
{
public class Startup
{
public void Configuration(IAppBuilder builder)
{
builder
.UseApiResponseCompression()
....
}
}
}
But i really excited hypothetical opportunities to use this middleware in appropriate controller or method ( I've seen such functionality implementation in asp.net core)
Q: Is it possible to use arbitrary middleware in specific controller or ever method ( like filters) in asp.net web api2?
Will MiddlewareFilter do what you are expecting?
You create a pipeline class, say MyPipeline, which has one method with signature public void Configure(IApplicationBuilder applicationBuilder). Then place [MiddlewareFilter(typeof(MyPipeline))] on the controller or action.

Define NServiceBus instance-mapping in code

I'm writing an asp.net core application and wanna send a message to an NServiceBus endpoint.
As we have different environments I need to configure an endpoint address for each environment. I do that in the app settings.Env.json.
I like to do the same with the instance mappings. The only ways I know is to have a different instance-mapping.xml file for every environment or add it to the app.config that I don't have. Is there a way to set the instance machine in code? I don't wanna have different XML files.
I use NServiceBus 6.3.4
I added a feature to the endpoint configuration:
endpointConfiguration.EnableFeature<MyFeature>();
public class MyFeature : Feature
{
protected override void Setup(FeatureConfigurationContext context)
{
var endpointInstances = context.Settings.Get<EndpointInstances>();
endpointInstances.AddOrReplaceInstances("InstanceMapping",
new List<EndpointInstance>
{
new EndpointInstance("MyEndpoint").AtMachine("VM-1")
});
}
}
Check docs here and here

in ASP.NET Core, is there any way to set up middleware from Program.cs?

I am building a support library for ASP.NET Core websites. I have a few pieces of middleware that need to be enabled, and they need to be added before any other middleware due what they do.
I can create an extension method on IWebHostBuilder to add services, likewise for configuring logging, but I don't see any way to add middleware in a programmatic way. Is there any way to do this? Looking at the source for WebHost/WebHostBuilder nothing jumped out.
Given the first comment, I may not have been clear enough. I know how to create middleware and use it. What I am trying to do is ensure that when the Configure(IApplicationBuilder app) method is called on Startup by the framework, my middleware is already in place. In a similar manner to being able to do ServiceConfiguration prior to Startup even being created. So an extension method like
public static IWebHostBuilder AddPayscaleHostingServices(this IWebHostBuilder webHostBuilder, string serviceName)
{
return webHostBuilder.ConfigureServices(collection =>
{
collection.RegisterPayscaleHostingServices();
}).ConfigureLogging(factory =>
{
});
}
gives me the ability to do some setup prior to the webHostBuilder.Build method, but I don't see anything similar for middleware/anything on IApplicationBuilder.
Thanks,
Erick
You could use a startup filter to achieve this. Startup filters allow you to configure middleware from a service resolved from the DI container.
Defining a startup filter is easy:
public class MyStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return app =>
{
// Configure middleware
// ...
// Call the next configure method
next(app);
};
}
}
Always make sure to call next(app) or any other middleware won't be configured.
Now register the startup filter as a singleton implementation of IStartupFilter in your ConfigureServices method:
services.AddSingleton<IStartupFilter, MyStartupFilter>();

Application startup code in ASP.NET Core

Reading over the documentation for ASP.NET Core, there are two methods singled out for Startup: Configure and ConfigureServices.
Neither of these seemed like a good place to put custom code that I would like to run at startup. Perhaps I want to add a custom field to my DB if it doesn't exist, check for a specific file, seed some data into my database, etc. Code that I want to run once, just at app start.
Is there a preferred/recommended approach for going about doing this?
I agree with the OP.
My scenario is that I want to register a microservice with a service registry but have no way of knowing what the endpoint is until the microservice is running.
I feel that both the Configure and ConfigureServices methods are not ideal because neither were designed to carry out this kind of processing.
Another scenario would be wanting to warm up the caches, which again is something we might want to do.
There are several alternatives to the accepted answer:
Create another application which carries out the updates outside of your website, such as a deployment tool, which applies the database updates programmatically before starting the website
In your Startup class, use a static constructor to ensure the website is ready to be started
Update
The best thing to do in my opinion is to use the IApplicationLifetime interface like so:
public class Startup
{
public void Configure(IApplicationLifetime lifetime)
{
lifetime.ApplicationStarted.Register(OnApplicationStarted);
}
public void OnApplicationStarted()
{
// Carry out your initialisation.
}
}
This can be done by creating an IHostedService implementation and registering it using IServiceCollection.AddHostedService<>() in ConfigureServices() in your startup class.
Example
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
public class MyInitializer : IHostedService
{
public Task StartAsync(CancellationToken cancellationToken)
{
// Do your startup work here
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
// We have to implement this method too, because it is in the interface
return Task.CompletedTask;
}
}
using Microsoft.Extensions.DependencyInjection;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHostedService<MyInitializer>();
}
}
Notes
The main application will not be started until after your code has finished executing.
Constructor dependency injection is available to the IHostedService implementation.
I can recommend this blog post for more info, and an example of how to use async: https://andrewlock.net/running-async-tasks-on-app-startup-in-asp-net-core-3/
For more background reading, see this discussion: https://github.com/dotnet/aspnetcore/issues/10137
Basically there are two entry points for such custom code at startup time.
1.) Main method
As a ASP.NET Core application has got the good old Main method as entry point you could place code before the ASP.NET Core startup stuff, like
public class Program
{
public static void Main(string[] args)
{
// call custom startup logic here
AppInitializer.Startup();
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
2.) Use your Startup class
As you already stated in your question is the Configure and ConfigureServices a good place for your custom code.
I would prefer the Startup class. From the runtime perspective it does not matter, if the call is called in startup or somewhere else before the host.Run() call. But from a programmer's point of view who is accustomed to the ASP.NET framework then his first look for such logic would be the Startup.cs file. All samples and templates put there the logic for Identity, Entity Framework initialization and so on. So as a convention I recommend to place the initialization stuff there.

Categories