Search code examples
c#asp.net-coreblazorxaf

Inject asp.net core middleware from inside a library to a specific location


I am developing a plugin and I need to inject another middleware into the user StartUp.cs, is there a way to it without modifying the user StartUp.cs?

The only way I can think of is actually patching the runtime and inject the required IL instructions to the start of UseXaf middleware that call my middleware first. However I am hoping there is build-in mechanism to it.

if(env.IsDevelopment()) {
    app.UseDeveloperExceptionPage();
}
else {
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();

//INJECT IT HERE <---------

app.UseXaf();

Solution

  • My solution was to actually patch the runtime and inject instructions to call my custom middleware just before the the UseXaf middleware.

    It can be done easy with the https://github.com/pardeike/Harmony library as:

        public class UseHangfire : IStartupFilter {
            private static readonly Harmony Harmony=new Harmony(nameof(UseHangfire));
            static UseHangfire() {
                var methodInfo = typeof(StartupExtensions).Method(nameof(StartupExtensions.UseXaf),Flags.StaticPublic);
                Harmony.Patch(methodInfo,postfix:new HarmonyMethod(typeof(UseHangfire),nameof(UseXaf))); //runtime patching of the UseXaf middleware
            }
    
            public static void UseXaf(IApplicationBuilder builder) => Dashboard?.Invoke(builder); //inject the Hangfire Dashboard and authorize before UseXaf is used
    
            public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) => next;
    
            public static Action<IApplicationBuilder> Dashboard = builder 
                => builder.UseHangfireDashboard(options:new DashboardOptions {Authorization = new[] {new DashboardAuthorization()}
            });
        }
    
        public class DashboardAuthorization : IDashboardAuthorizationFilter {
            public bool Authorize(DashboardContext context)
                => context.GetHttpContext().User.Identity.IsAuthenticated;
        }
    
        public class HangfireStartup : IHostingStartup{
            public void Configure(IWebHostBuilder builder) 
                => builder.ConfigureServices(services => services
                    .AddSingleton<IStartupFilter, UseHangfire>()
                );
        }
    
    

    in the stripped out snippet you can see how I used the asp.net core IHostingStartup inside my library to register an IStartupFilter which in his turn patch at runtime the UseXaf middleware (with the OHarmony library) to call the UseHangfireDashboard middleware at the exact point I needed.

    Harder to describe in English that to type in C# :)

    Caveats: depending on what actually want to patch you should be aware that compiler might inline it or not for different frameworks. Read more on their wiki Inlining