aspnet / AspNetKatana

Microsoft's OWIN implementation, the Katana project
Apache License 2.0
967 stars 334 forks source link

Is there any plan to add "UseWhen" extension? #147

Closed hmalli closed 4 years ago

Tratcher commented 6 years ago

This one? https://github.com/aspnet/HttpAbstractions/blob/87cd79d6fc54bb4abf07c1e380cd7a9498a78612/src/Microsoft.AspNetCore.Http.Abstractions/Extensions/UseWhenExtensions.cs#L23

No, but it's trivial for you to add to your app. You can copy that code and replace the builder type.

hmalli commented 6 years ago

It's complaining about the following line. Katana doesn't seem to have Use extension with following signature. Am i missing something?

return app.Use(main =>
            {
                // This is called only when the main application builder 
                // is built, not per request.
                branchBuilder.Run(main);
                var branch = branchBuilder.Build();

                return context =>
                {
                    if (predicate(context))
                    {
                        return branch(context);
                    }
                    else
                    {
                        return main(context);
                    }
                };
            });
Tratcher commented 6 years ago
using System;
using Microsoft.Owin;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace Owin
{
    using Predicate = Func<IOwinContext, bool>;
    using AppFunc = Func<IDictionary<string, object>, Task>;

    /// <summary>
    /// Extension methods for <see cref="IApplicationBuilder"/>.
    /// </summary>
    public static class UseWhenExtensions
    {
        /// <summary>
        /// Conditionally creates a branch in the request pipeline that is rejoined to the main pipeline.
        /// </summary>
        /// <param name="app"></param>
        /// <param name="predicate">Invoked with the request environment to determine if the branch should be taken</param>
        /// <param name="configuration">Configures a branch to take</param>
        /// <returns></returns>
        public static IAppBuilder UseWhen(this IAppBuilder app, Predicate predicate, Action<IAppBuilder> configuration)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }

            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }

            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            // Create and configure the branch builder right away; otherwise,
            // we would end up running our branch after all the components
            // that were subsequently added to the main builder.
            var branchBuilder = app.New();
            configuration(branchBuilder);

            return app.Use(new Func<AppFunc, AppFunc>(main =>
            {
                // This is called only when the main application builder 
                // is built, not per request.
                branchBuilder.Run(context => main(context.Environment));
                var branch = (AppFunc)branchBuilder.Build(typeof(AppFunc));

                return context =>
                {
                    if (predicate(new OwinContext(context)))
                    {
                        return branch(context);
                    }
                    else
                    {
                        return main(context);
                    }
                };
            }));
        }
    }
}
hmalli commented 6 years ago

that works. thank you!

kuehnd96 commented 4 years ago

Thank you for providing the UseWhen() method. I am using it and having some trouble running either of two branches of middleware. My code from my Configuration() method is below. I am seeing both sets of middleware run for each request regardless of the result of my isIntegratedTenant predicate. I know because I am seeing both instances of LogAuthMiddleware run. Any ideas why this is happening? I will double-check my predicate. Thank you. (This is .NET framework 4.7.2)

app.UseWhen(context => isIntegratedTenant(context), appBuilder =>
{
    app.Use(typeof(LogAuthMiddleware), "Using Auth0 authentication for URL '{0}'.");

    app.UseAuth0(); // my own extension method using multiple calls to Use()

    // All cookies need to be same-site compatible since clients host this application in iFrames
    app.UseSameSiteCookies(SameSitePolicy.None);
});

app.UseWhen(context => !isIntegratedTenant(context), appBuilder =>
{
    app.Use(typeof(LogAuthMiddleware), "Using Forms authentication for URL '{0}'.");

    // Forms authentication
   app.UseCookieAuthentication(new CookieAuthenticationOptions()
   {
       AuthenticationMode = AuthenticationMode.Active,
       LoginPath = new PathString("/Login.aspx"),
       CookieName = "WhitewaterAnalytics",
       CookieSecure = CookieSecureOption.Never,
       CookiePath = "/",
       ExpireTimeSpan = new TimeSpan(0, Constants.Authentication.TimeoutMinutes, 0)
    });
});
Tratcher commented 4 years ago

Classic mistake. You're using app rather than appBuilder to build the branches. Try this:

app.UseWhen(context => isIntegratedTenant(context), appBuilder =>
{
    appBuilder.Use(typeof(LogAuthMiddleware), "Using Auth0 authentication for URL '{0}'.");

    appBuilder.UseAuth0(); // my own extension method using multiple calls to Use()

    // All cookies need to be same-site compatible since clients host this application in iFrames
    appBuilder.UseSameSiteCookies(SameSitePolicy.None);
});
kuehnd96 commented 4 years ago

I appreciate you showing me the way. I noticed this about 10 minutes after I posted my comment. Closures for the win. It works now. Thank you.