Ocelot icon indicating copy to clipboard operation
Ocelot copied to clipboard

Use custom pipeline middleware implemented as a class instead of a Func delegate

Open ghost opened this issue 6 years ago • 8 comments

Expected Behavior / New Feature

Be able to create a custom middleware implementation like:

public class CustomAuthorizationMiddleware : OcelotMiddleware
{
        private readonly RequestDelegate _next;

        public CustomAuthorisationMiddleware(
            RequestDelegate next,
            IOcelotLoggerFactory loggerFactory)
            :base(loggerFactory.CreateLogger<CustomAuthorizationMiddleware>())
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            // logic goes here
        }
}

Actual Behavior / Motivation for New Feature

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            var configuration = new OcelotPipelineConfiguration
            {
                AuthorizationMiddleware = async (context, next) =>
                {
                    // Logic goes here
                    await next.Invoke();
                }
            };
            
            app.UseOcelot(configuration)
                .Wait();
        }

ghost avatar Nov 23 '18 17:11 ghost

I really needed that myself and ended up building some tooling for it that you can find here : https://gist.github.com/cguyonnet/650ca02ac87e33ea24814f0cb3e7e852

Basically it will generate an OcelotPipelineConfiguration that will encapsulate your class-based middleware...

cguyonnet avatar Mar 01 '19 15:03 cguyonnet

Sweet! Thanks a lot

ghost avatar Mar 01 '19 15:03 ghost

@cguyonnet Thanks a lot! This really helped in my case. I needed to update the headers of the downstream calls with values I get from other services. The ability to get dependencies injected into the Ocelot middleware was crucial for this flow and your code works like a charm for this. Thanks again 😄

pilgren avatar Mar 19 '20 14:03 pilgren

Hi, team when we can implement this one, so i can use nuget without change the source code?

charzhao avatar Jan 17 '22 08:01 charzhao

@ghost commented on Nov 23, 2018

Well... It is interesting... Do you believe that delegates are restriction for you but middleware classes are not, right? But you can define local services variable with all services from DI container like that:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        var configuration = new OcelotPipelineConfiguration
        {
            AuthorizationMiddleware = async (context, next) =>
            {
                var service1 = app.ApplicationServices.GetService<IService1>();
                var service2 = app.ApplicationServices.GetService<IService2>();

                var obj1 = service1.DoSomething1();
                var obj2 = service2.DoSomething2();

                // Logic goes here
                await next.Invoke();
            }
        };
           
        app.UseOcelot(configuration).Wait();
    }

If it looks ugly for you then you could encapsulate logic into a class:

public class CustomAuthorizationMiddleware : OcelotMiddleware
{
    private readonly OcelotRequestDelegate _next;

    public CustomAuthorizationMiddleware(
        OcelotRequestDelegate next,
        IOcelotLoggerFactory loggerFactory)
        : base(loggerFactory.CreateLogger<CustomAuthorizationMiddleware>())
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        // logic goes here
       await _next.Invoke(context);
    }
}

and

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        var factory = app.ApplicationServices.GetService<IOcelotLoggerFactory>();
        var configuration = new OcelotPipelineConfiguration
        {
            AuthorizationMiddleware = async (context, next) =>
            {
                RequestDelegate del = context => next.Invoke();
                var middleware = new CustomAuthorizationMiddleware(del, factory);
                await middleware.Invoke(context);
            }
        };
           
        app.UseOcelot(configuration).Wait();
    }

This design approach above doesn't require huge refactoring of Ocelot core and pipeline, in comparison to the @cguyonnet solution on Mar 1, 2019.

raman-m avatar Jan 07 '24 13:01 raman-m

@cguyonnet commented on Mar 1, 2019

Great design & solution! 🤩 But unfortunately it has no backward compatibility. Seems it has a lot of breaking changes. Your opinion?

raman-m avatar Jan 07 '24 13:01 raman-m

@pilgren commented on Mar 19, 2020

You can process your headers by custom Delegating Handler 😉 So, no need to write custom middleware and attach to the pipeline with overriding standard Ocelot middleware.

raman-m avatar Jan 07 '24 13:01 raman-m