Как вернуться в корень конвейера после выполнения ветки? - PullRequest
0 голосов
/ 28 сентября 2018

В конвейере OWIN я использую ветку для настройки пользовательского промежуточного программного обеспечения аутентификации.Как вернуться в корень конвейера после выполнения ветки?

app.Use<AuthenticationMiddleware1>();
app.Map("/branch", (application) => {
    application.Use<AuthenticationMiddleware2>();
});
app.UseWebApi(new HttpConfiguration());

Когда я запрашиваю http://server/branch, веб-API не настроен и возвращает 404

Я пытался написать MapAndContinueMiddleware:

public class MapAndContinueMiddleware:OwinMiddleware
{
    public MapAndContinueMiddleware(OwinMiddleware next, MapOptions options) : base(next)
    {
        this.Options = options;
    }

    public MapOptions Options { get; }


    public async override Task Invoke(IOwinContext context)
    {
        if(context.Request.Path.StartsWithSegments(this.Options.PathMatch))
        {
            await this.Options.Branch(context).ContinueWith((previousTask) =>
            {
                this.Next.Invoke(context);
            });
        }
        else
        {
            await this.Next.Invoke(context);
        }
    }
}

с этим расширением:

public static IAppBuilder MapAndContinue(this IAppBuilder app, string pathMatch, Action<IAppBuilder> configuration)
{
    // create branch and assign to options
    IAppBuilder branch = app.New();
    configuration(branch);

    MapOptions options = new MapOptions {
        PathMatch = new PathString(pathMatch),
        Branch = (Func<IOwinContext, Task>)branch.Build(typeof(Func<IOwinContext, Task>))
    };
    return MapAndContinue(app, options);
}

public static IAppBuilder MapAndContinue(this IAppBuilder app, MapOptions options)
{
    return app.Use<MapAndContinueMiddleware>(options);
}

Но это странное поведение: веб-запрос API запускает ветку дважды и не возвращается клиенту ...!?

1 Ответ

0 голосов
/ 03 октября 2018

Вы пытались продолжить конвейер, настроенный после ветки

var config = new HttpConfiguration();
app.Use<AuthenticationMiddleware1>();
app.Map("/branch", (application) => {
    application.Use<AuthenticationMiddleware2>();
    application.UseWebApi(config);
});
app.UseWebApi(config);

Таким образом, после ветки он все еще сможет использовать Web API

Просмотр ОригиналаMapExtension Источник может показаться, что порядок добавления промежуточного программного обеспечения в конвейер важен

Просмотрите следующий рефакторинг, чтобы использовать свое промежуточное ПО для пользовательской карты

using AppFunc = Func<IDictionary<string, object>, Task>;

//...

public static class BranchAndMergeExtensions {

    public static IAppBuilder MapAndContinue(this IAppBuilder app, string pathMatch, Action<IAppBuilder> configuration) {
        return MapAndContinue(app, new PathString(pathMatch), configuration);
    }

    public static IAppBuilder MapAndContinue(this IAppBuilder app, PathString pathMatch, Action<IAppBuilder> configuration) {
        if (app == null) {
            throw new ArgumentNullException("app");
        }
        if (configuration == null) {
            throw new ArgumentNullException("configuration");
        }
        if (pathMatch.HasValue && pathMatch.Value.EndsWith("/", StringComparison.Ordinal)) {
            throw new ArgumentException("Path must not end with slash '/'", "pathMatch");
        }

        // put middleware in pipeline before creating branch
        var options = new MapOptions { PathMatch = pathMatch };
        var result = app.Use<MapAndContinueMiddleware>(options);

        // create branch and assign to options
        IAppBuilder branch = app.New();
        configuration(branch);
        options.Branch = (AppFunc)branch.Build(typeof(AppFunc));

        return result;
    }
}

original MapMiddleware также необходимо провести рефакторинг, чтобы не допустить его короткого замыкания в конвейере, позволяя корневому конвейеру быть вызванным после ветви.

public class MapAndContinueMiddleware : OwinMiddleware {
    private readonly MapOptions options;

    public MapAndContinueMiddleware(OwinMiddleware next, MapOptions options)
        : base(next) {
        this.options = options;
    }

    public async override Task Invoke(IOwinContext context) {
        PathString path = context.Request.Path;
        PathString remainingPath;
        if (path.StartsWithSegments(options.PathMatch, out remainingPath)) {
            // Update the path
            PathString pathBase = context.Request.PathBase;
            context.Request.PathBase = pathBase + options.PathMatch;
            context.Request.Path = remainingPath;

            //call branch delegate
            await this.options.Branch(context.Environment);

            context.Request.PathBase = pathBase;
            context.Request.Path = path;
        }
        // call next delegate
        await this.Next.Invoke(context);
    }
}

Что в итоге приводит к вашемуисходный пример установки становится

var config = new HttpConfiguration();
app.Use<AuthenticationMiddleware1>();
app.MapAndContinue("/branch", (application) => {
    application.Use<AuthenticationMiddleware2>();
});
app.UseWebApi(config);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...