2

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();
Apostolis Bekiaris
  • 2,145
  • 2
  • 18
  • 21
  • 1
    I think this question is still a bit unclear, about some constraints you pose on both the current user project & your plugin system. E.g: if we have full flexibility to modify the user code & design the plugin system accordingly, we can use normal DI to inject the services (loading module to build on the `IApplicationBuilder`), of course that extensibility point must be setup by placing a stub to where the user need in the `Configure` method (like where you pointed out in the question). – King King Jan 22 '21 at 19:22
  • I will update my answer to make it crystal clear then. – Apostolis Bekiaris Jan 22 '21 at 21:38
  • 1
    I'm not so sure how your plugin system works, but there are surely 2 cases: a plugin will run before & after the code in the `Startup.cs`. Either ways may require a different approach to solve it. I'm pretty sure that there is no built-in mechanism to achieve what you want. Even a simple requirement to get all the registered middlewares need a hacky code (playing around with reflection, referencing the source code, ...). Anyway, the first problem you need to solve is how to target the point of injection before actually injecting the code. Hope you can solve this yourself, it's really tough :) – King King Jan 23 '21 at 23:34
  • > a plugin will run before & after the code in the Startup.cs I know about IStartupFilter >the first problem you need to solve is how to target the point of injection The User Startup.cs is fixed, the UseXaf middleware always exist, the injection must be done exactly before it. – Apostolis Bekiaris Jan 24 '21 at 09:28

2 Answers2

2

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

Apostolis Bekiaris
  • 2,145
  • 2
  • 18
  • 21
1

You can create your own custom Middleware class. This can either be by implementing the IMiddleware interface or just creating a class with a public method named Invoke or InvokeAsync. To add the middleware to your pipeline you can create a static method like so:

public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder builder)
{
    return builder.UseMiddleware<CustomMiddleware>();
}

then in Startup.cs:

app.UseCustomMiddleware();

See this page for more information on middleware.

SBFrancies
  • 3,987
  • 2
  • 14
  • 37