Asp.Net final Core EndPoint enrutamiento principio de interpretación

I. Antecedentes

En va a escribir un artículo sobre este Identityserver4 artículo, se encontraron en EndPoint - la expedición punto final no es muy comprensiva, por lo que ser el primero en abandonar la IdentityServer4 investigación y la escritura; por lo que tuvieron hoy sobre este EndPoint artículo (punto final de enrutamiento) de.

O, como de costumbre, abrir la potencia de los ordenadores de Google y Baidu acceso a los motores de búsqueda a la información pertinente, así como de núcleo abierto código fuente Asp.net 3.1 leí, y, finalmente, en mi práctica y pruebas para EndPoint tener una comprensión diferente, diciendo aquí es más que admirar en la tubería para el modelo de diseño de la estructura del núcleo Asp.net 3.x de Microsoft.

Me gustaría plantear las siguientes preguntas:

1. Cuando se accede a una dirección de aplicación Web, Asp.Net Core es cómo llevar a cabo Controller en Actionél? 2. Endpoint con la vía ordinaria y no es qué tipo de relación? 3 UseRouing() , UseAuthorization(), UserEndpoints() la relación entre estos tres middleware ¿Qué es? 4. cómo el uso Endpoint de escribir su propio middleware y escenarios de aplicación de punto final (por un tiempo limitado, consolidación de la acción la próxima vez)

En segundo lugar, lea las dudas de código fuente

Startup código

En primer vistazo a Startupla versión simplificada del código, el código es el siguiente:

public void ConfigureServices(IServiceCollection services){        services.AddControllers();}public void Configure(IApplicationBuilder app, IWebHostEnvironment env){        app.UseRouting();        app.UseAuthorization();        app.UseEndpoints(endpoints =>        {              endpoints.MapControllers();        });}

Programa fase de puesta en marcha:

Paso 1: Ejecutar services.AddControllers () los Controllerservicios básicos registrados al recipiente a

El segundo paso: la implementación de app.UseRouting () se EndpointRoutingMiddlewaremiddleware registro para http oleoducto

El tercer paso: la implementación de app.UseAuthorization () se AuthorizationMiddlewaremiddleware registro para http oleoducto

El cuarto paso: realizar app.UseEndpoints (encpoints => endpoints.MapControllers () ) tiene dos funciones principales: llamada endpoints.MapControllers()a un conjunto definido de todo el programa Controllery Actionconvertir el uno EndPointen el middleware objeto de configuración de enrutamiento RouteOptionsen el EndpointMiddlewaremedio inscripciones para tubería http

app.UseRouting() El código fuente es el siguiente:

public static IApplicationBuilder UseRouting(this IApplicationBuilder builder){       if (builder == null)       {             throw new ArgumentNullException(nameof(builder));       }       VerifyRoutingServicesAreRegistered(builder);       var endpointRouteBuilder = new DefaultEndpointRouteBuilder(builder);       builder.Properties[EndpointRouteBuilder] = endpointRouteBuilder;       return builder.UseMiddleware<EndpointRoutingMiddleware>(endpointRouteBuilder); }

EndpointRoutingMiddleware middleware de código es el siguiente:

internal sealed 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 maching 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;                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            {                var matcher = _matcherFactory.CreateMatcher(_endpointDataSource);                // Now replace the initialization task with one created with the default execution context.                // This is important because capturing the execution context will leak memory in ASP.NET Core.                using (ExecutionContext.SuppressFlow())                {                    _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 class Log        {            private static readonly Action<ILogger, string, Exception> _matchSuccess = LoggerMessage.Define<string>(                LogLevel.Debug,                new EventId(1, "MatchSuccess"),                "Request matched endpoint '{EndpointName}'");            private static readonly Action<ILogger, Exception> _matchFailure = LoggerMessage.Define(                LogLevel.Debug,                new EventId(2, "MatchFailure"),                "Request did not match any endpoints");            private static readonly Action<ILogger, string, Exception> _matchingSkipped = LoggerMessage.Define<string>(                LogLevel.Debug,                new EventId(3, "MatchingSkipped"),                "Endpoint '{EndpointName}' already set, skipping route matching.");            public static void MatchSuccess(ILogger logger, Endpoint endpoint)            {                _matchSuccess(logger, endpoint.DisplayName, null);            }            public static void MatchFailure(ILogger logger)            {                _matchFailure(logger, null);            }            public static void MatchSkipped(ILogger logger, Endpoint endpoint)            {                _matchingSkipped(logger, endpoint.DisplayName, null);            }        }    }

Podemos ver desde el código fuente, EndpointRoutingMiddlewaremiddleware creado por primera vez matcher, y luego llamar matcher.MatchAsync(httpContext)para encontrar puntos finales, y, finalmente, por httpContext.GetEndpoint()si el partido se ha verificado a la derecha Endpointy cruzar un lado Middleware continúa!

app.UseEndpoints() fuente

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>();}internal class DefaultEndpointRouteBuilder : IEndpointRouteBuilder{        public DefaultEndpointRouteBuilder(IApplicationBuilder applicationBuilder)        {            ApplicationBuilder = applicationBuilder ?? throw new ArgumentNullException(nameof(applicationBuilder));            DataSources = new List<EndpointDataSource>();        }        public IApplicationBuilder ApplicationBuilder { get; }        public IApplicationBuilder CreateApplicationBuilder() => ApplicationBuilder.New();        public ICollection<EndpointDataSource> DataSources { get; }        public IServiceProvider ServiceProvider => ApplicationBuilder.ApplicationServices;    }

Código construido DefaultEndpointRouteBuilder punto final de enrutamiento objeto constructor, que se almacena en Endpointun conjunto de transacciones; Terminator mientras que los datos almacenados en el conjunto de rutas routeOptions en el registro y el EndpointMiddleware conducto intermedio a http;  Endpointcódigo objeto como sigue:

/// <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; }        public override string ToString() => DisplayName ?? base.ToString();    }

Endpoint Hay dos claves tipo de código de objeto de atributo son EndpointMetadataCollection Tipo y RequestDelegate:

   EndpointMetadataCollection: tiendas Controller y Actionconjunto asociado de elementos que comprenden Action los Attribute datos característicos         RequestDelegate : Acción es decir, la comisión almacenado, este es un método de controlador de acción por

Y luego volver al EndpointMiddleware middleware y el código del núcleo, EndpointMiddleware un código de núcleo grande es la implementación de punto final de RequestDelegate la comisión, a saber, Controller la Action ejecución.

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            {                 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);             }         }}

Las dudas Respuesta:

1. Cuando se accede a una dirección de aplicación Web, Asp.Net Core es cómo llevar a cabo Controller en Actionél?

A: El programa se inicia cuando el mapeo de acción almacenada en el controlador, con toda routeOptions de la colección, Acción mapeadas en Endpointel Terminator RequestDelegate confió propiedad, y finalmente por UseEndPoints la adición de EndpointMiddleware middleware ejecución, mientras que el middleware Endpoint ruta Terminator es a través Rouingdespués de expulsar el partido.

2.  EndPoint con la vía ordinaria y no es qué tipo de relación?

A: Ednpoint ruta Terminator está encargado por la ruta ordinaria después de la conversión mapa de ruta, que contiene todos los elementos del mensaje método de enrutamiento EndpointMetadataCollection y RequestDelegate delegado.

UseRouing() , UseAuthorization(), UseEndpoints() la relación entre estos tres middleware ¿Qué es?

R: UseRouing Middleware se dirige principalmente partido, encontrar los correspondientes ruta Terminator Endpoint ; UseEndpoints middleware para las principales UseRouing ejecución de la operación métodos partido middleware delegado ruta. UseAuthorization Middleware dirigido  UseRouing para el juego de enrutamiento middleware qué operación de verificación de autorización de interceptación, se realiza a través de los siguientes intermedios UseEndpoints()relaciones, en particular puede ser visto en el siguiente diagrama de flujo:

En el diagrama de flujo por encima de omitir algunas partes, principalmente el UseRouing relación resaltado, UseAuthorization, UseEndpoint tres middleware.

Publicados 309 artículos originales · ganado elogios 119 · Vistas de 460.000 +

Supongo que te gusta

Origin blog.csdn.net/u011966339/article/details/104747816
Recomendado
Clasificación