netcore无线路由器_netcore路由器怎么设置

netcore无线路由器_netcore路由器怎么设置IdentityServer里有各种Endpoint,如TokenEndpoint,UserInfoEndpoint,AuthorizeEndpoint,DiscoveryEndpoint等等。E

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

    IdentityServer里有各种Endpoint,如TokenEndpoint,UserInfoEndpoint,Authorize Endpoint,Discovery Endpoint等等。Endpoint从字面意思来看是“终端节点”或者“终节点”的意思。无独有偶NetCore的路由也有Endpoint的概念。那么我们提出一个问题来,究竟什么是Endpoint?

    先来看一段代码,如下所示:

    

netcore无线路由器_netcore路由器怎么设置
netcore无线路由器_netcore路由器怎么设置

public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.ConfigureServices(svcs => svcs.AddRouting()).Configure(
                        
                        app => app.UseRouting().UseEndpoints(
                        //test1
                        //endpoints => endpoints.MapGet("weather/{city}/{days}", 

                        //test2
                          endpoints =>endpoints.MapGet("weather/{city}/{year}.{month}.{day}", WeatherForecast)
                        
                        
                          ));
                });

        private static Dictionary<string, string> _cities = new Dictionary<string, string>() {
            ["001"]="Beijing",
            ["028"]="Chengdu",
            ["091"]="Suzhou"
        
        };

        //RequestDelegate
        public static async Task WeatherForecast(HttpContext context)
        {
            var city = (string)context.GetRouteData().Values["city"];
            city = _cities[city];
           
            //test1
            //int days=int.Parse(context.GetRouteData().Values["days"].ToString());
            //var report = new WeatherReport(city, days);

            //test2
            int year = int.Parse(context.GetRouteData().Values["year"].ToString());
            int month= int.Parse(context.GetRouteData().Values["month"].ToString());
            int day=int.Parse(context.GetRouteData().Values["day"].ToString());
            var report = new WeatherReport(city, new DateTime(year, month, day));
            await RenderWeatherAsync(context, report);
        }

        private static async Task RenderWeatherAsync(HttpContext context,WeatherReport report)
        {
            context.Response.ContentType = "text/html;charset=utf-8";
            await context.Response.WriteAsync("<html><head><title>Weather</title></head><body>");
            await context.Response.WriteAsync($"<h3>{report.City}</h3>");
            foreach(var it in report.WeatherInfos)
            {
                await context.Response.WriteAsync($"{it.Key.ToString("yyyy-MM-dd")}: ");
                await context.Response.WriteAsync($"{it.Value.LowTemperature}--{it.Value.HighTemperature} <br/>");
            }
            await context.Response.WriteAsync("</body></html>");
        }
    }

View Code

 

 

上面的代码很清晰,如果路由格式匹配”weather/{city}/{year}.{month}.{day}”,那么就调用WeatherForecast方法,这里的app.UseRouting().UseEndpoints就用到了Endpoint模式。要了解Endpoint,我们需要抽丝剥茧一步一步了解几个类的方法:

   1.我们先看最里面的endpoints =>endpoints.MapGet(“weather/{city}/{year}.{month}.{day}”, WeatherForecast),这里实际上调用的是EndpointRouteBuilderExtensions类的MapGet方法,代码如下所示:

 

netcore无线路由器_netcore路由器怎么设置
netcore无线路由器_netcore路由器怎么设置

    /// <summary>
    /// Provides extension methods for <see cref="IEndpointRouteBuilder"/> to add endpoints.
    /// </summary>
    public static class EndpointRouteBuilderExtensions
    {
        // Avoid creating a new array every call
        private static readonly string[] GetVerb = new[] { "GET" };
        private static readonly string[] PostVerb = new[] { "POST" };
        private static readonly string[] PutVerb = new[] { "PUT" };
        private static readonly string[] DeleteVerb = new[] { "DELETE" };
        private static readonly string[] PatchVerb = new[] { "PATCH" };
        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP GET requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="requestDelegate">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
        public static IEndpointConventionBuilder MapGet(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            RequestDelegate requestDelegate)
        {
            return MapMethods(endpoints, pattern, GetVerb, requestDelegate);
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP POST requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="requestDelegate">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
        public static IEndpointConventionBuilder MapPost(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            RequestDelegate requestDelegate)
        {
            return MapMethods(endpoints, pattern, PostVerb, requestDelegate);
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP PUT requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="requestDelegate">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
        public static IEndpointConventionBuilder MapPut(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            RequestDelegate requestDelegate)
        {
            return MapMethods(endpoints, pattern, PutVerb, requestDelegate);
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP DELETE requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="requestDelegate">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
        public static IEndpointConventionBuilder MapDelete(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            RequestDelegate requestDelegate)
        {
            return MapMethods(endpoints, pattern, DeleteVerb, requestDelegate);
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP PATCH requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="requestDelegate">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
        public static IEndpointConventionBuilder MapPatch(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            RequestDelegate requestDelegate)
        {
            return MapMethods(endpoints, pattern, PatchVerb, requestDelegate);
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests
        /// for the specified HTTP methods and pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="requestDelegate">The delegate executed when the endpoint is matched.</param>
        /// <param name="httpMethods">HTTP methods that the endpoint will match.</param>
        /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
        public static IEndpointConventionBuilder MapMethods(
           this IEndpointRouteBuilder endpoints,
           string pattern,
           IEnumerable<string> httpMethods,
           RequestDelegate requestDelegate)
        {
            if (httpMethods == null)
            {
                throw new ArgumentNullException(nameof(httpMethods));
            }

            var builder = endpoints.Map(RoutePatternFactory.Parse(pattern), requestDelegate);
            builder.WithDisplayName($"{pattern} HTTP: {string.Join(", ", httpMethods)}");
            builder.WithMetadata(new HttpMethodMetadata(httpMethods));
            return builder;
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="requestDelegate">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
        public static IEndpointConventionBuilder Map(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            RequestDelegate requestDelegate)
        {
            return Map(endpoints, RoutePatternFactory.Parse(pattern), requestDelegate);
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="requestDelegate">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
        public static IEndpointConventionBuilder Map(
            this IEndpointRouteBuilder endpoints,
            RoutePattern pattern,
            RequestDelegate requestDelegate)
        {
            if (endpoints == null)
            {
                throw new ArgumentNullException(nameof(endpoints));
            }

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

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

            const int defaultOrder = 0;

            //实例化RouteEndpointBuilder
            var builder = new RouteEndpointBuilder(
                requestDelegate,
                pattern,
                defaultOrder)
            {
                DisplayName = pattern.RawText ?? pattern.DebuggerToString(),
            };

            // Add delegate attributes as metadata
            var attributes = requestDelegate.Method.GetCustomAttributes();

            // This can be null if the delegate is a dynamic method or compiled from an expression tree
            if (attributes != null)
            {
                foreach (var attribute in attributes)
                {
                    builder.Metadata.Add(attribute);
                }
            }

            //Adds a RouteEndpoint to the IEndpointRouteBuilder that matches HTTP requests
            /// for the specified pattern.
            ///可以理解为:将某种格式的路由pattern添加至IEndpointRouteBuilder的DataSource属性,为match做准备 
            var dataSource = endpoints.DataSources.OfType<ModelEndpointDataSource>().FirstOrDefault();
            if (dataSource == null)
            {
                dataSource = new ModelEndpointDataSource();
                endpoints.DataSources.Add(dataSource);
            }

            return dataSource.AddEndpointBuilder(builder);
        }


        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP GET requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="handler">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
        public static RouteHandlerBuilder MapGet(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            Delegate handler)
        {
            return MapMethods(endpoints, pattern, GetVerb, handler);
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP POST requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="handler">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
        public static RouteHandlerBuilder MapPost(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            Delegate handler)
        {
            return MapMethods(endpoints, pattern, PostVerb, handler);
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP PUT requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="handler">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
        public static RouteHandlerBuilder MapPut(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            Delegate handler)
        {
            return MapMethods(endpoints, pattern, PutVerb, handler);
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP DELETE requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="handler">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
        public static RouteHandlerBuilder MapDelete(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            Delegate handler)
        {
            return MapMethods(endpoints, pattern, DeleteVerb, handler);
        }


        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP PATCH requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="handler">The <see cref="Delegate" /> executed when the endpoint is matched.</param>
        /// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
        public static RouteHandlerBuilder MapPatch(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            Delegate handler)
        {
            return MapMethods(endpoints, pattern, PatchVerb, handler);
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests
        /// for the specified HTTP methods and pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="handler">The delegate executed when the endpoint is matched.</param>
        /// <param name="httpMethods">HTTP methods that the endpoint will match.</param>
        /// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
        public static RouteHandlerBuilder MapMethods(
           this IEndpointRouteBuilder endpoints,
           string pattern,
           IEnumerable<string> httpMethods,
           Delegate handler)
        {
            if (httpMethods is null)
            {
                throw new ArgumentNullException(nameof(httpMethods));
            }

            var disableInferredBody = false;
            foreach (var method in httpMethods)
            {
                disableInferredBody = ShouldDisableInferredBody(method);
                if (disableInferredBody is true)
                {
                    break;
                }
            }

            var builder = endpoints.Map(RoutePatternFactory.Parse(pattern), handler, disableInferredBody);
            // Prepends the HTTP method to the DisplayName produced with pattern + method name
            builder.Add(b => b.DisplayName = $"HTTP: {string.Join(", ", httpMethods)} {b.DisplayName}");
            builder.WithMetadata(new HttpMethodMetadata(httpMethods));
            return builder;

            static bool ShouldDisableInferredBody(string method)
            {
                 // GET, DELETE, HEAD, CONNECT, TRACE, and OPTIONS normally do not contain bodies
                return method.Equals(HttpMethods.Get, StringComparison.Ordinal) ||
                       method.Equals(HttpMethods.Delete, StringComparison.Ordinal) ||
                       method.Equals(HttpMethods.Head, StringComparison.Ordinal) ||
                       method.Equals(HttpMethods.Options, StringComparison.Ordinal) ||
                       method.Equals(HttpMethods.Trace, StringComparison.Ordinal) ||
                       method.Equals(HttpMethods.Connect, StringComparison.Ordinal);
            }
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="handler">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
        public static RouteHandlerBuilder Map(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            Delegate handler)
        {
            return Map(endpoints, RoutePatternFactory.Parse(pattern), handler);
        }

        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="handler">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
        public static RouteHandlerBuilder Map(
            this IEndpointRouteBuilder endpoints,
            RoutePattern pattern,
            Delegate handler)
        {
            return Map(endpoints, pattern, handler, disableInferBodyFromParameters: false);
        }

        /// <summary>
        /// Adds a specialized <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that will match
        /// requests for non-file-names with the lowest possible priority.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="handler">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
        /// <remarks>
        /// <para>
        /// <see cref="MapFallback(IEndpointRouteBuilder, Delegate)"/> is intended to handle cases where URL path of
        /// the request does not contain a file name, and no other endpoint has matched. This is convenient for routing
        /// requests for dynamic content to a SPA framework, while also allowing requests for non-existent files to
        /// result in an HTTP 404.
        /// </para>
        /// <para>
        /// <see cref="MapFallback(IEndpointRouteBuilder, Delegate)"/> registers an endpoint using the pattern
        /// <c>{*path:nonfile}</c>. The order of the registered endpoint will be <c>int.MaxValue</c>.
        /// </para>
        /// </remarks>
        public static RouteHandlerBuilder MapFallback(this IEndpointRouteBuilder endpoints, Delegate handler)
        {
            if (endpoints == null)
            {
                throw new ArgumentNullException(nameof(endpoints));
            }

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

            return endpoints.MapFallback("{*path:nonfile}", handler);
        }

        /// <summary>
        /// Adds a specialized <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that will match
        /// the provided pattern with the lowest possible priority.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="handler">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
        /// <remarks>
        /// <para>
        /// <see cref="MapFallback(IEndpointRouteBuilder, string, Delegate)"/> is intended to handle cases where no
        /// other endpoint has matched. This is convenient for routing requests to a SPA framework.
        /// </para>
        /// <para>
        /// The order of the registered endpoint will be <c>int.MaxValue</c>.
        /// </para>
        /// <para>
        /// This overload will use the provided <paramref name="pattern"/> verbatim. Use the <c>:nonfile</c> route constraint
        /// to exclude requests for static files.
        /// </para>
        /// </remarks>
        public static RouteHandlerBuilder MapFallback(
            this IEndpointRouteBuilder endpoints,
            string pattern,
            Delegate handler)
        {
            if (endpoints == null)
            {
                throw new ArgumentNullException(nameof(endpoints));
            }

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

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

            var conventionBuilder = endpoints.Map(pattern, handler);
            conventionBuilder.WithDisplayName("Fallback " + pattern);
            conventionBuilder.Add(b => ((RouteEndpointBuilder)b).Order = int.MaxValue);
            return conventionBuilder;
        }

        private static RouteHandlerBuilder Map(
            this IEndpointRouteBuilder endpoints,
            RoutePattern pattern,
            Delegate handler,
            bool disableInferBodyFromParameters)
        {
            if (endpoints is null)
            {
                throw new ArgumentNullException(nameof(endpoints));
            }

            if (pattern is null)
            {
                throw new ArgumentNullException(nameof(pattern));
            }

            if (handler is null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            const int defaultOrder = 0;

            var routeParams = new List<string>(pattern.Parameters.Count);
            foreach (var part in pattern.Parameters)
            {
                routeParams.Add(part.Name);
            }

            var routeHandlerOptions = endpoints.ServiceProvider?.GetService<IOptions<RouteHandlerOptions>>();

            var options = new RequestDelegateFactoryOptions
            {
                ServiceProvider = endpoints.ServiceProvider,
                RouteParameterNames = routeParams,
                ThrowOnBadRequest = routeHandlerOptions?.Value.ThrowOnBadRequest ?? false,
                DisableInferBodyFromParameters = disableInferBodyFromParameters,
            };

            var requestDelegateResult = RequestDelegateFactory.Create(handler, options);

            var builder = new RouteEndpointBuilder(
                requestDelegateResult.RequestDelegate,
                pattern,
                defaultOrder)
            {
                DisplayName = pattern.RawText ?? pattern.DebuggerToString(),
            };

            // REVIEW: Should we add an IActionMethodMetadata with just MethodInfo on it so we are
            // explicit about the MethodInfo representing the "handler" and not the RequestDelegate?

            // Add MethodInfo as metadata to assist with OpenAPI generation for the endpoint.
            builder.Metadata.Add(handler.Method);

            // Methods defined in a top-level program are generated as statics so the delegate
            // target will be null. Inline lambdas are compiler generated method so they can
            // be filtered that way.
            if (GeneratedNameParser.TryParseLocalFunctionName(handler.Method.Name, out var endpointName)
                || !TypeHelper.IsCompilerGeneratedMethod(handler.Method))
            {
                endpointName ??= handler.Method.Name;
                builder.DisplayName = $"{builder.DisplayName} => {endpointName}";
            }

            // Add delegate attributes as metadata
            var attributes = handler.Method.GetCustomAttributes();

            // Add add request delegate metadata
            foreach (var metadata in requestDelegateResult.EndpointMetadata)
            {
                builder.Metadata.Add(metadata);
            }

            // This can be null if the delegate is a dynamic method or compiled from an expression tree
            if (attributes is not null)
            {
                foreach (var attribute in attributes)
                {
                    builder.Metadata.Add(attribute);
                }
            }

            var dataSource = endpoints.DataSources.OfType<ModelEndpointDataSource>().FirstOrDefault();
            if (dataSource is null)
            {
                dataSource = new ModelEndpointDataSource();
                endpoints.DataSources.Add(dataSource);
            }

            return new RouteHandlerBuilder(dataSource.AddEndpointBuilder(builder));
        }
    }
}

View Code

 

在这里我们重点看看下面签名的方法:

 

netcore无线路由器_netcore路由器怎么设置
netcore无线路由器_netcore路由器怎么设置

 /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="requestDelegate">The delegate executed when the endpoint is matched.</param>
        /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
        public static IEndpointConventionBuilder Map(
            this IEndpointRouteBuilder endpoints,
            RoutePattern pattern,
            RequestDelegate requestDelegate)
        {
            if (endpoints == null)
            {
                throw new ArgumentNullException(nameof(endpoints));
            }

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

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

            const int defaultOrder = 0;

            //实例化RouteEndpointBuilder
            var builder = new RouteEndpointBuilder(
                requestDelegate,
                pattern,
                defaultOrder)
            {
                DisplayName = pattern.RawText ?? pattern.DebuggerToString(),
            };

            // Add delegate attributes as metadata
            var attributes = requestDelegate.Method.GetCustomAttributes();

            // This can be null if the delegate is a dynamic method or compiled from an expression tree
            if (attributes != null)
            {
                foreach (var attribute in attributes)
                {
                    builder.Metadata.Add(attribute);
                }
            }

            //Adds a RouteEndpoint to the IEndpointRouteBuilder that matches HTTP requests
            /// for the specified pattern.
            ///可以理解为:将某种格式的路由pattern添加至IEndpointRouteBuilder的DataSource属性,为match做准备 
            var dataSource = endpoints.DataSources.OfType<ModelEndpointDataSource>().FirstOrDefault();
            if (dataSource == null)
            {
                dataSource = new ModelEndpointDataSource();
                endpoints.DataSources.Add(dataSource);
            }

            return dataSource.AddEndpointBuilder(builder);
        }

View Code

 

在这个方法里有一个实例化RouteEndpointBuilder的语句:

  var builder = new RouteEndpointBuilder(
                requestDelegate,
                pattern,
                defaultOrder)
            {
                DisplayName = pattern.RawText ?? pattern.DebuggerToString(),
            };

 

其中RouteEndpointBuilder从字面意思看得出,就是RouteEndpoint的创建者,我们看下它的代码:

netcore无线路由器_netcore路由器怎么设置
netcore无线路由器_netcore路由器怎么设置

 public sealed class RouteEndpointBuilder : EndpointBuilder
    {
        /// <summary>
        /// Gets or sets the <see cref="RoutePattern"/> associated with this endpoint.
        /// </summary>
        public RoutePattern RoutePattern { get; set; }

        /// <summary>
        ///  Gets or sets the order assigned to the endpoint.
        /// </summary>
        public int Order { get; set; }

        /// <summary>
        /// Constructs a new <see cref="RouteEndpointBuilder"/> instance.
        /// </summary>
        /// <param name="requestDelegate">The delegate used to process requests for the endpoint.</param>
        /// <param name="routePattern">The <see cref="RoutePattern"/> to use in URL matching.</param>
        /// <param name="order">The order assigned to the endpoint.</param>
        public RouteEndpointBuilder(
           RequestDelegate requestDelegate,
           RoutePattern routePattern,
           int order)
        {
            RequestDelegate = requestDelegate;
            RoutePattern = routePattern;
            Order = order;
        }

        //生成Route
        /// <inheritdoc />
        public override Endpoint Build()
        {
            if (RequestDelegate is null)
            {
                throw new InvalidOperationException($"{nameof(RequestDelegate)} must be specified to construct a {nameof(RouteEndpoint)}.");
            }

            var routeEndpoint = new RouteEndpoint(
                RequestDelegate,
                RoutePattern,
                Order,
                new EndpointMetadataCollection(Metadata),
                DisplayName);

            return routeEndpoint;
        }
    }

View Code

 

再来看下Endpoint的代码:

netcore无线路由器_netcore路由器怎么设置
netcore无线路由器_netcore路由器怎么设置

   /// <summary>
    /// Represents a logical endpoint in an application.
    /// </summary>
    public class Endpoint
    {
        /// <summary>
        /// Creates a new instance of <see cref="Endpoint"/>.
        /// </summary>
        /// <param name="requestDelegate">The delegate used to process requests for the endpoint.</param>
        /// <param name="metadata">
        /// The endpoint <see cref="EndpointMetadataCollection"/>. May be null.
        /// </param>
        /// <param name="displayName">
        /// The informational display name of the endpoint. May be null.
        /// </param>
        public Endpoint(
            RequestDelegate? requestDelegate,
            EndpointMetadataCollection? metadata,
            string? displayName)
        {
            // All are allowed to be null
            RequestDelegate = requestDelegate;
            Metadata = metadata ?? EndpointMetadataCollection.Empty;
            DisplayName = displayName;
        }

        /// <summary>
        /// Gets the informational display name of this endpoint.
        /// </summary>
        public string? DisplayName { get; }

        /// <summary>
        /// Gets the collection of metadata associated with this endpoint.
        /// </summary>
        public EndpointMetadataCollection Metadata { get; }

        /// <summary>
        /// Gets the delegate used to process requests for the endpoint.
        /// </summary>
        public RequestDelegate? RequestDelegate { get; }

        /// <summary>
        /// Returns a string representation of the endpoint.
        /// </summary>
        public override string? ToString() => DisplayName ?? base.ToString();
    }

View Code

 

从Build()方法看得出,它利用路由匹配的RoutePattern,生成一个RouteEndpoint实例。RouteEndpoint叫做路由终点,继承自Endpoint。Endpoint有一个重要的RequestDelegate属性,用来处理当前的请求。看到这里,我们开始推断:所谓的Endpoint,无非就是用要匹配的pattern,构造一个RouteEndpoint的过程,其中RouteEndpoint继承自Endpoint。NetCore无非就是利用这个RouteEndpoint来匹配当前的Url,如果匹配得上,就执行RequestDelegate所代表的方法,上文就是WeatherForecast方法,如果匹配不上,则不执行WeatherForecast方法,仅此而已。

  2.为了验证,我们再来看 app.UseRouting().UseEndpoints(),实际上调用的是EndpointRoutingApplicationBuilderExtensions类的两个方法:

netcore无线路由器_netcore路由器怎么设置
netcore无线路由器_netcore路由器怎么设置

   public static class EndpointRoutingApplicationBuilderExtensions
    {
        private const string EndpointRouteBuilder = "__EndpointRouteBuilder";
        private const string GlobalEndpointRouteBuilderKey = "__GlobalEndpointRouteBuilder";

        /// <summary>
        /// Adds a <see cref="EndpointRoutingMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>.
        /// </summary>
        /// <param name="builder">The <see cref="IApplicationBuilder"/> to add the middleware to.</param>
        /// <returns>A reference to this instance after the operation has completed.</returns>
        /// <remarks>
        /// <para>
        /// A call to <see cref="UseRouting(IApplicationBuilder)"/> must be followed by a call to
        /// <see cref="UseEndpoints(IApplicationBuilder, Action{IEndpointRouteBuilder})"/> for the same <see cref="IApplicationBuilder"/>
        /// instance.
        /// </para>
        /// <para>
        /// The <see cref="EndpointRoutingMiddleware"/> defines a point in the middleware pipeline where routing decisions are
        /// made, and an <see cref="Endpoint"/> is associated with the <see cref="HttpContext"/>. The <see cref="EndpointMiddleware"/>
        /// defines a point in the middleware pipeline where the current <see cref="Endpoint"/> is executed. Middleware between
        /// the <see cref="EndpointRoutingMiddleware"/> and <see cref="EndpointMiddleware"/> may observe or change the
        /// <see cref="Endpoint"/> associated with the <see cref="HttpContext"/>.
        /// </para>
        /// </remarks>
        public static IApplicationBuilder UseRouting(this IApplicationBuilder builder)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            VerifyRoutingServicesAreRegistered(builder);

            IEndpointRouteBuilder endpointRouteBuilder;
            if (builder.Properties.TryGetValue(GlobalEndpointRouteBuilderKey, out var obj))
            {
                endpointRouteBuilder = (IEndpointRouteBuilder)obj!;
                // Let interested parties know if UseRouting() was called while a global route builder was set
                builder.Properties[EndpointRouteBuilder] = endpointRouteBuilder;
            }
            else
            {
                endpointRouteBuilder = new DefaultEndpointRouteBuilder(builder);
                builder.Properties[EndpointRouteBuilder] = endpointRouteBuilder;
            }

            //先交由EndpointRoutingMiddleware中间件匹配Endpoint,然后交由下面的EndpointMiddleware处理
            return builder.UseMiddleware<EndpointRoutingMiddleware>(endpointRouteBuilder);
        }

        /// <summary>
        /// Adds a <see cref="EndpointMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>
        /// with the <see cref="EndpointDataSource"/> instances built from configured <see cref="IEndpointRouteBuilder"/>.
        /// The <see cref="EndpointMiddleware"/> will execute the <see cref="Endpoint"/> associated with the current
        /// request.
        /// </summary>
        /// <param name="builder">The <see cref="IApplicationBuilder"/> to add the middleware to.</param>
        /// <param name="configure">An <see cref="Action{IEndpointRouteBuilder}"/> to configure the provided <see cref="IEndpointRouteBuilder"/>.</param>
        /// <returns>A reference to this instance after the operation has completed.</returns>
        /// <remarks>
        /// <para>
        /// A call to <see cref="UseEndpoints(IApplicationBuilder, Action{IEndpointRouteBuilder})"/> must be preceded by a call to
        /// <see cref="UseRouting(IApplicationBuilder)"/> for the same <see cref="IApplicationBuilder"/>
        /// instance.
        /// </para>
        /// <para>
        /// The <see cref="EndpointRoutingMiddleware"/> defines a point in the middleware pipeline where routing decisions are
        /// made, and an <see cref="Endpoint"/> is associated with the <see cref="HttpContext"/>. The <see cref="EndpointMiddleware"/>
        /// defines a point in the middleware pipeline where the current <see cref="Endpoint"/> is executed. Middleware between
        /// the <see cref="EndpointRoutingMiddleware"/> and <see cref="EndpointMiddleware"/> may observe or change the
        /// <see cref="Endpoint"/> associated with the <see cref="HttpContext"/>.
        /// </para>
        /// </remarks>
        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)
            {
                if (!routeOptions.Value.EndpointDataSources.Contains(dataSource))
                {
                    routeOptions.Value.EndpointDataSources.Add(dataSource);
                }
            }

            //交由EndpointMiddleware处理
            return builder.UseMiddleware<EndpointMiddleware>();
        }

        private static void VerifyRoutingServicesAreRegistered(IApplicationBuilder app)
        {
            // Verify if AddRouting was done before calling UseEndpointRouting/UseEndpoint
            // We use the RoutingMarkerService to make sure if all the services were added.
            if (app.ApplicationServices.GetService(typeof(RoutingMarkerService)) == null)
            {
                throw new InvalidOperationException(Resources.FormatUnableToFindServices(
                    nameof(IServiceCollection),
                    nameof(RoutingServiceCollectionExtensions.AddRouting),
                    "ConfigureServices(...)"));
            }
        }

        private static void VerifyEndpointRoutingMiddlewareIsRegistered(IApplicationBuilder app, out IEndpointRouteBuilder endpointRouteBuilder)
        {
            if (!app.Properties.TryGetValue(EndpointRouteBuilder, out var obj))
            {
                var message =
                    $"{nameof(EndpointRoutingMiddleware)} matches endpoints setup by {nameof(EndpointMiddleware)} and so must be added to the request " +
                    $"execution pipeline before {nameof(EndpointMiddleware)}. " +
                    $"Please add {nameof(EndpointRoutingMiddleware)} by calling '{nameof(IApplicationBuilder)}.{nameof(UseRouting)}' inside the call " +
                    $"to 'Configure(...)' in the application startup code.";
                throw new InvalidOperationException(message);
            }

            endpointRouteBuilder = (IEndpointRouteBuilder)obj!;

            // This check handles the case where Map or something else that forks the pipeline is called between the two
            // routing middleware.
            if (endpointRouteBuilder is DefaultEndpointRouteBuilder defaultRouteBuilder && !object.ReferenceEquals(app, defaultRouteBuilder.ApplicationBuilder))
            {
                var message =
                    $"The {nameof(EndpointRoutingMiddleware)} and {nameof(EndpointMiddleware)} must be added to the same {nameof(IApplicationBuilder)} instance. " +
                    $"To use Endpoint Routing with 'Map(...)', make sure to call '{nameof(IApplicationBuilder)}.{nameof(UseRouting)}' before " +
                    $"'{nameof(IApplicationBuilder)}.{nameof(UseEndpoints)}' for each branch of the middleware pipeline.";
                throw new InvalidOperationException(message);
            }
        }
    }

View Code

   2-1首先看UseRouting()方法,这个方法其实就是调用EndpointRoutingMiddleware中间件进行Endpoint的匹配,我们可以看下它的几个方法:

  

netcore无线路由器_netcore路由器怎么设置
netcore无线路由器_netcore路由器怎么设置

internal sealed partial class EndpointRoutingMiddleware
    {
        private const string DiagnosticsEndpointMatchedKey = "Microsoft.AspNetCore.Routing.EndpointMatched";

        private readonly MatcherFactory _matcherFactory;
        private readonly ILogger _logger;
        private readonly EndpointDataSource _endpointDataSource;
        private readonly DiagnosticListener _diagnosticListener;
        private readonly RequestDelegate _next;

        private Task<Matcher>? _initializationTask;

        public EndpointRoutingMiddleware(
            MatcherFactory matcherFactory,
            ILogger<EndpointRoutingMiddleware> logger,
            IEndpointRouteBuilder endpointRouteBuilder,
            DiagnosticListener diagnosticListener,
            RequestDelegate next)
        {
            if (endpointRouteBuilder == null)
            {
                throw new ArgumentNullException(nameof(endpointRouteBuilder));
            }

            _matcherFactory = matcherFactory ?? throw new ArgumentNullException(nameof(matcherFactory));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            _diagnosticListener = diagnosticListener ?? throw new ArgumentNullException(nameof(diagnosticListener));
            _next = next ?? throw new ArgumentNullException(nameof(next));

            _endpointDataSource = new CompositeEndpointDataSource(endpointRouteBuilder.DataSources);
        }

        public Task Invoke(HttpContext httpContext)
        {
            // There's already an endpoint, skip matching completely
            var endpoint = httpContext.GetEndpoint();
            if (endpoint != null)
            {
                Log.MatchSkipped(_logger, endpoint);
                return _next(httpContext);
            }

            // There's an inherent race condition between waiting for init and accessing the matcher
            // this is OK because once `_matcher` is initialized, it will not be set to null again.
            var matcherTask = InitializeAsync();
            if (!matcherTask.IsCompletedSuccessfully)
            {
                return AwaitMatcher(this, httpContext, matcherTask);
            }

            var matchTask = matcherTask.Result.MatchAsync(httpContext);
            if (!matchTask.IsCompletedSuccessfully)
            {
                return AwaitMatch(this, httpContext, matchTask);
            }

            return SetRoutingAndContinue(httpContext);

            // Awaited fallbacks for when the Tasks do not synchronously complete
            static async Task AwaitMatcher(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task<Matcher> matcherTask)
            {
                var matcher = await matcherTask;
                //根据httpContext进行匹配
                await matcher.MatchAsync(httpContext);
                await middleware.SetRoutingAndContinue(httpContext);
            }

            static async Task AwaitMatch(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task matchTask)
            {
                await matchTask;
                await middleware.SetRoutingAndContinue(httpContext);
            }

        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private Task SetRoutingAndContinue(HttpContext httpContext)
        {
            // If there was no mutation of the endpoint then log failure
            var endpoint = httpContext.GetEndpoint();
            if (endpoint == null)
            {
                Log.MatchFailure(_logger);
            }
            else
            {
                // Raise an event if the route matched
                if (_diagnosticListener.IsEnabled() && _diagnosticListener.IsEnabled(DiagnosticsEndpointMatchedKey))
                {
                    // We're just going to send the HttpContext since it has all of the relevant information
                    _diagnosticListener.Write(DiagnosticsEndpointMatchedKey, httpContext);
                }

                Log.MatchSuccess(_logger, endpoint);
            }

            return _next(httpContext);
        }

        // Initialization is async to avoid blocking threads while reflection and things
        // of that nature take place.
        //
        // We've seen cases where startup is very slow if we  allow multiple threads to race
        // while initializing the set of endpoints/routes. Doing CPU intensive work is a
        // blocking operation if you have a low core count and enough work to do.
        private Task<Matcher> InitializeAsync()
        {
            var initializationTask = _initializationTask;
            if (initializationTask != null)
            {
                return initializationTask;
            }

            return InitializeCoreAsync();
        }

        private Task<Matcher> InitializeCoreAsync()
        {
            var initialization = new TaskCompletionSource<Matcher>(TaskCreationOptions.RunContinuationsAsynchronously);
            var initializationTask = Interlocked.CompareExchange(ref _initializationTask, initialization.Task, null);
            if (initializationTask != null)
            {
                // This thread lost the race, join the existing task.
                return initializationTask;
            }

            // This thread won the race, do the initialization.
            try
            {
                //用EndpointDataSource初始化matcher
                //EndpointDataSource来源于IEndpointRouteBuilder的DataSource属性
                //见EndpointRouteBuilderExtensions类的201行
                var matcher = _matcherFactory.CreateMatcher(_endpointDataSource);

                _initializationTask = Task.FromResult(matcher);

                // Complete the task, this will unblock any requests that came in while initializing.
                initialization.SetResult(matcher);
                return initialization.Task;
            }
            catch (Exception ex)
            {
                // Allow initialization to occur again. Since DataSources can change, it's possible
                // for the developer to correct the data causing the failure.
                _initializationTask = null;

                // Complete the task, this will throw for any requests that came in while initializing.
                initialization.SetException(ex);
                return initialization.Task;
            }
        }

        private static partial class Log
        {
            public static void MatchSuccess(ILogger logger, Endpoint endpoint)
                => MatchSuccess(logger, endpoint.DisplayName);

            [LoggerMessage(1, LogLevel.Debug, "Request matched endpoint '{EndpointName}'", EventName = "MatchSuccess")]
            private static partial void MatchSuccess(ILogger logger, string? endpointName);

            [LoggerMessage(2, LogLevel.Debug, "Request did not match any endpoints", EventName = "MatchFailure")]
            public static partial void MatchFailure(ILogger logger);

            public static void MatchSkipped(ILogger logger, Endpoint endpoint)
                => MatchingSkipped(logger, endpoint.DisplayName);

            [LoggerMessage(3, LogLevel.Debug, "Endpoint '{EndpointName}' already set, skipping route matching.", EventName = "MatchingSkipped")]
            private static partial void MatchingSkipped(ILogger logger, string? endpointName);
        }
    }

View Code

从Invoke方法看得出来,它根据当前的HttpContext进行Endpoint的匹配,如果当前的HttpContext路由格式匹配成功,那么将当前HttpContext传递给下一个中间件处理,这个从SetRoutingAndContinue方法看得出来。

 

 2-2其次看下UseEndpoints()方法,这个方法就是调用EndpointMiddleware中间件,对上面匹配成功的HttpContext进行处理,并调用HttpContext的EndPoint的RequestDelegate处理当前请求。我们重点看下它的Invoke方法,重点关注var requestTask = endpoint.RequestDelegate(httpContext):

netcore无线路由器_netcore路由器怎么设置
netcore无线路由器_netcore路由器怎么设置

  public Task Invoke(HttpContext httpContext)
        {
            var endpoint = httpContext.GetEndpoint();
            if (endpoint?.RequestDelegate != null)
            {
                if (!_routeOptions.SuppressCheckForUnhandledSecurityMetadata)
                {
                    if (endpoint.Metadata.GetMetadata<IAuthorizeData>() != null &&
                        !httpContext.Items.ContainsKey(AuthorizationMiddlewareInvokedKey))
                    {
                        ThrowMissingAuthMiddlewareException(endpoint);
                    }

                    if (endpoint.Metadata.GetMetadata<ICorsMetadata>() != null &&
                        !httpContext.Items.ContainsKey(CorsMiddlewareInvokedKey))
                    {
                        ThrowMissingCorsMiddlewareException(endpoint);
                    }
                }

                Log.ExecutingEndpoint(_logger, endpoint);

                try
                {
                    //调用HttpContext的Endpoint的RequestDelegate方法处理当前请求
                    var requestTask = endpoint.RequestDelegate(httpContext);
                    if (!requestTask.IsCompletedSuccessfully)
                    {
                        return AwaitRequestTask(endpoint, requestTask, _logger);
                    }
                }
                catch (Exception exception)
                {
                    Log.ExecutedEndpoint(_logger, endpoint);
                    return Task.FromException(exception);
                }

                Log.ExecutedEndpoint(_logger, endpoint);
                return Task.CompletedTask;
            }

            return _next(httpContext);

            static async Task AwaitRequestTask(Endpoint endpoint, Task requestTask, ILogger logger)
            {
                try
                {
                    await requestTask;
                }
                finally
                {
                    Log.ExecutedEndpoint(logger, endpoint);
                }
            }
        }

View Code

 

  总结:从上面的分析,我们粗略的了解了netcore路由的Endpoint模式其实就是一种用匹配模式构建的终端节点,它主要用来对HttpContext进行路由的匹配,如果匹配成功,则执行Endpoint上的RequestDelegate方法。

 

 

  

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/170755.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 初识CDN加速

    初识CDN加速

  • verifycode.php,verifycode.php

    verifycode.php,verifycode.php##生成验证码文件session_start();header(“Content-type:image/png”);##生成验证码图片$str=”1,2,3,4,5,6,7,8,9″;##要显示的字符,可自己进行增删$list=explode(“,”,$str);$cmax=count($list)-1;$verifyCode=”;for($i=0;$i<…

  • 存储过程常见语法

    存储过程常见语法存储过程常见语法一、存储过程的概念:1、存储过程Procedure是一组为了完成特定功能的SQL语句集合,经编译后存储在数据库中,用户通过指定存储过程的名称并给出参数来执行2、存储过程中可以包含逻辑控制语句和数据操纵语句,它可以接受参数、输出参数、返回单个或多个结果集以及返回值。3、由于存储过程在创建时即在数据库服务器上进行了编译并存储在数据库中,所以存储过程运行要比单个的SQL语…

  • java实现邮件发送_显示对方是qq邮箱发短信

    java实现邮件发送_显示对方是qq邮箱发短信java实现手机短信和邮箱推送

    2022年10月13日
  • BigDecimal转为int类型「建议收藏」

    BigDecimal转为int类型「建议收藏」直接调用BigDecimal的intValue()方法示例:BigDecimala=newBigDecimal(“1.1”);intb=a.intValue();

    2022年10月29日
  • MySQL忘记密码怎么修改密码[通俗易懂]

    MySQL忘记密码怎么修改密码[通俗易懂]MySQL的root帐号密码默认为空,经常都有修改密码后忘记密码的事。如果忘记了root帐号密码,那该怎么修改密码呢?这里有一个可行的方法,就是在MySQL安全模式下(跳过权限检查)修改密码的方式来解决这个问题。本文分别对Windows环境与Linux环境下介绍MySQL忘记密码时修改密码的方法,希望帮助初学者解决丢失密码的烦恼。

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号