在asp.net-core中使用app.run和app.useendpoints有什么区别?

时间:2019-10-17 12:43:42

标签: c# .net asp.net-core .net-core asp.net-core-2.0

我是asp.net-core的新手,我对app.run和app.useendpoints感到困惑,两者之间有什么区别?它们的劣势有一些优点吗?我尝试在3.0中使用app.run,但不确定是否有必要?有人可以建议吗?

2 个答案:

答案 0 :(得分:1)

对于app.Run,它将终端中间件委托添加到应用程序的请求管道中。

对于app.Use,它将中间件委托添加到应用程序的请求管道中。

对于app.Runapp.UseEndpoints之间的差异,它是app.Runapp.Use之间的差异。 app.Run将结束请求,而app.Use会将请求传递给下一个中间件。

对于app.UseEndpoints,它是app.UseEndpointMiddleware

一些关键代码,例如:

    public static IApplicationBuilder UseEndpoints(this IApplicationBuilder builder, Action<IEndpointRouteBuilder> configure)
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }

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

        VerifyRoutingServicesAreRegistered(builder);

        VerifyEndpointRoutingMiddlewareIsRegistered(builder, out var endpointRouteBuilder);

        configure(endpointRouteBuilder);

        // Yes, this mutates an IOptions. We're registering data sources in a global collection which
        // can be used for discovery of endpoints or URL generation.
        //
        // Each middleware gets its own collection of data sources, and all of those data sources also
        // get added to a global collection.
        var routeOptions = builder.ApplicationServices.GetRequiredService<IOptions<RouteOptions>>();
        foreach (var dataSource in endpointRouteBuilder.DataSources)
        {
            routeOptions.Value.EndpointDataSources.Add(dataSource);
        }

        return builder.UseMiddleware<EndpointMiddleware>();
    }

UseMidleware类似于

    public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app, Type middleware, params object[] args)
    {
        if (typeof(IMiddleware).GetTypeInfo().IsAssignableFrom(middleware.GetTypeInfo()))
        {
            // IMiddleware doesn't support passing args directly since it's
            // activated from the container
            if (args.Length > 0)
            {
                throw new NotSupportedException(Resources.FormatException_UseMiddlewareExplicitArgumentsNotSupported(typeof(IMiddleware)));
            }

            return UseMiddlewareInterface(app, middleware);
        }

        var applicationServices = app.ApplicationServices;
        return app.Use(next =>
        {
            var methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public);
            var invokeMethods = methods.Where(m =>
                string.Equals(m.Name, InvokeMethodName, StringComparison.Ordinal)
                || string.Equals(m.Name, InvokeAsyncMethodName, StringComparison.Ordinal)
                ).ToArray();

            if (invokeMethods.Length > 1)
            {
                throw new InvalidOperationException(Resources.FormatException_UseMiddleMutlipleInvokes(InvokeMethodName, InvokeAsyncMethodName));
            }

            if (invokeMethods.Length == 0)
            {
                throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoInvokeMethod(InvokeMethodName, InvokeAsyncMethodName, middleware));
            }

            var methodInfo = invokeMethods[0];
            if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
            {
                throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNonTaskReturnType(InvokeMethodName, InvokeAsyncMethodName, nameof(Task)));
            }

            var parameters = methodInfo.GetParameters();
            if (parameters.Length == 0 || parameters[0].ParameterType != typeof(HttpContext))
            {
                throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoParameters(InvokeMethodName, InvokeAsyncMethodName, nameof(HttpContext)));
            }

            var ctorArgs = new object[args.Length + 1];
            ctorArgs[0] = next;
            Array.Copy(args, 0, ctorArgs, 1, args.Length);
            var instance = ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs);
            if (parameters.Length == 1)
            {
                return (RequestDelegate)methodInfo.CreateDelegate(typeof(RequestDelegate), instance);
            }

            var factory = Compile<object>(methodInfo, parameters);

            return context =>
            {
                var serviceProvider = context.RequestServices ?? applicationServices;
                if (serviceProvider == null)
                {
                    throw new InvalidOperationException(Resources.FormatException_UseMiddlewareIServiceProviderNotAvailable(nameof(IServiceProvider)));
                }

                return factory(instance, context, serviceProvider);
            };
        });
    }

答案 1 :(得分:0)

区别是基本的,爱德华在解释方面做得很好,但我相信更简单的解释会更好。 App.Use 用于向 OWIN 管道添加中间件,App.Run 也用于相同目的。不同之处在于,一旦添加了 App.Run 的中间件完成其执行,管道将终止并且响应将返回给调用者。这是唯一的区别。让我举个例子。

app.Use((context, nextMidWare) => { context.Response.Body.Write("Written by app.Use"); nextMidWare(context);});

app.Run((context) => context.Response.Body.Write("Written by app.Run"));

app.Use((context, nextMidWare) => context.Response.Body.Write("Also written by app.Use"));

为了更好地传达我的解释,我稍微简化了方法签名。鉴于这些是唯一注册的中间件,当您从浏览器请求网站时,结果将如下所示。

Written by app.Use
Written by app.Run

正如您所看到的,最后一条消息“Also write by app.Use”尚未写入响应。原因当然是我们在使用 App.Run 注册了另一个中间件之后注册了关联的中间件。如果我们使用 App.Use 代替,那么我们也会观察到最后一条消息。

最后,App.UseEndpoints 类似于对 App.Use 方法的预配置调用,它为您提供某些功能,我建议您阅读一些关于此问题的 Microsoft 文档。

我建议您阅读以下内容: