Post
MiddlewareBuilder For ASP.NET Core 1.0 RC2
/ 3 min read
Found this post helpful?
Buy me a coffeeTable of Contents
I was reading Bill Boga’s ( @Bogaiv ) blog post “Environment name in ASP.NET Core 1.0 RC2” and noticed that the Configure method at the bottom of his post looked very iffy through no fault of his own.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { if (env.IsDevelopment()) { // do stuff on your local machine app.UseDeveloperExceptionPage(); app.UseBrowserLink(); }
if (env.IsStaging()) { // do stuff on your pre-prod. machine }
if (env.IsProduction()) { // do stuff on your prod. machine }
if (env.IsEnvironment("QA")) { // do stuff on your QA machine } }If you create a new ASP.NET Core 1.0 RC2 application using Visual Studio, the Configure method looks like this.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory){ loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug();
if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseDatabaseErrorPage(); app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); }
app.UseStaticFiles();
app.UseIdentity();
// Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715
app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });}Take note of the if/else block. I wanted to see if I could write a more fluent interface that accomplishes the same thing. This is my recreation of the default Configure method.
Another Approach
new MiddlewareBuilder(app, env) .Development((a, e) => { a.UseDeveloperExceptionPage() .UseDatabaseErrorPage() .UseBrowserLink(); }) .When(!env.IsDevelopment(), (a, e) => { a.UseExceptionHandler("/Home/Error"); }) .Always((a, e) => { a.UseStaticFiles() .UseIdentity() .UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }) .Build();I’m not sure I like my approach over the original if/else approach so I’d like your feedback. You can find the code below if you want to try out the MiddlewareBuilder.
Some caveats to keep in mind:
- The order of registration is determined inside the
MiddlewareBuilder MiddlewareBuilderonly supports one action per environment- tested very minimally
- registration only occurs once
Buildis called
The Code
public class MiddlewareBuilder{ const string AlwaysKey = "__always"; const string DevelopmentKey = "__development"; const string ProductionKey = "__production"; const string StagingKey = "__staging";
private readonly string[] allKeys = {AlwaysKey, DevelopmentKey, StagingKey, ProductionKey};
private Dictionary<string, Action<IHostingEnvironment, IApplicationBuilder>> Environments { get; } = new Dictionary<string, Action<IHostingEnvironment, IApplicationBuilder>>(StringComparer.CurrentCultureIgnoreCase);
private readonly IApplicationBuilder app; private readonly IHostingEnvironment env;
public MiddlewareBuilder(IApplicationBuilder app, IHostingEnvironment env) { if (env == null) throw new ArgumentNullException(nameof(env)); if (app == null) throw new ArgumentNullException(nameof(app));
this.env = env; this.app = app; }
public MiddlewareBuilder Always(Action<IHostingEnvironment, IApplicationBuilder> setup) { Environments.Add(AlwaysKey, setup); return this; }
public MiddlewareBuilder Development(Action<IHostingEnvironment, IApplicationBuilder> setup) { Environments.Add(DevelopmentKey, setup); return this; }
public MiddlewareBuilder Production(Action<IHostingEnvironment, IApplicationBuilder> setup) { Environments.Add(ProductionKey, setup); return this; }
public MiddlewareBuilder Staging(Action<IHostingEnvironment, IApplicationBuilder> setup) { Environments.Add(StagingKey, setup); return this; }
public void Build() { // always Action<IHostingEnvironment, IApplicationBuilder> always; Environments.TryGetValue(AlwaysKey, out always); always?.Invoke(env, app);
//development if (env.IsDevelopment()) { Action<IHostingEnvironment, IApplicationBuilder> development; Environments.TryGetValue(DevelopmentKey, out development); development?.Invoke(env, app); }
// staging if (env.IsStaging()) { Action<IHostingEnvironment, IApplicationBuilder> staging; Environments.TryGetValue(StagingKey, out staging); staging?.Invoke(env, app); }
// production if (env.IsProduction()) { Action<IHostingEnvironment, IApplicationBuilder> production; Environments.TryGetValue(StagingKey, out production); production?.Invoke(env, app); }
// remaining var remaining = Environments .Where(x => !allKeys.Contains(x.Key, StringComparer.CurrentCultureIgnoreCase)) .Where(x => env.IsEnvironment(x.Key)) .Select(x => x.Value);
foreach (var action in remaining) { action(env, app); } }}