Migración de controladores y módulos HTTP ASP.NET Core middleware
En este artículo se muestra cómo migrar los módulos y controladores ASP.NET HTTP existentes de system.webserver a ASP.NET Core middleware.
Módulos y controladores revisados
Antes de continuar ASP.NET Core middleware, vamos a recapitular primero cómo funcionan los módulos y controladores HTTP:

Los controladores son:
Clases que implementan IHttpHandler
Se usa para controlar las solicitudes con un nombre de archivo o extensión determinados, como .report.
Configurado en Web.config
Los módulos son:
Clases que implementan IHttpModule
Se invoca para cada solicitud
Capaz de cortocircuiciones (detener el procesamiento adicional de una solicitud)
Se puede agregar a la respuesta HTTP o crear la suya propia.
Configurado en Web.config
El orden en que los módulos procesan las solicitudes entrantes viene determinado por:
Eventos de serie desencadenados por ASP.NET, como BeginRequest y AuthenticateRequest . Para obtener una lista completa, vea System.Web.HttpApplication. Cada módulo puede crear un controlador para uno o varios eventos.
Para el mismo evento, el orden en que se configuran en Web.config.
Además de los módulos, puede agregar controladores para los eventos del ciclo de vida al archivo Global.asax.cs. Estos controladores se ejecutan después de los controladores de los módulos configurados.
Desde controladores y módulos hasta middleware
El middleware es más sencillo que los módulos y controladores HTTP:
Módulos, controladores, Global.asax.cs, Web.config(excepto la configuración de IIS) y el ciclo de vida de la aplicación han desaparecido
Los roles de los módulos y los controladores los ha asumido el middleware.
El middleware se configura mediante código en lugar de Web.config
- La bifurcación de canalizaciones permite enviar solicitudes a middleware específico, no solo en función de la dirección URL, sino también de encabezados de solicitud, cadenas de consulta, etc.
- La bifurcación de canalizaciones permite enviar solicitudes a middleware específico, no solo en función de la dirección URL, sino también de encabezados de solicitud, cadenas de consulta, etc.
El middleware es muy similar a los módulos:
Se invoca en principio para cada solicitud.
Se puede cortocircuidar una solicitud, sin pasar la solicitud al siguiente middleware
Capaz de crear su propia respuesta HTTP
El middleware y los módulos se procesan en un orden diferente:
El orden del middleware se basa en el orden en que se insertan en la canalización de solicitudes, mientras que el orden de los módulos se basa principalmente en System.Web.HttpApplication eventos.
El orden del middleware para las respuestas es el inverso al de las solicitudes, mientras que el orden de los módulos es el mismo para las solicitudes y respuestas.
Consulte Creación de una canalización de middleware con IApplicationBuilder

Observe cómo en la imagen anterior, el middleware de autenticación cortocircuió la solicitud.
Migración de código de módulo a middleware
Un módulo HTTP existente tendrá un aspecto similar al siguiente:
// ASP.NET 4 module
using System;
using System.Web;
namespace MyApp.Modules
{
public class MyModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication application)
{
application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
application.EndRequest += (new EventHandler(this.Application_EndRequest));
}
private void Application_BeginRequest(Object source, EventArgs e)
{
HttpContext context = ((HttpApplication)source).Context;
// Do something with context near the beginning of request processing.
}
private void Application_EndRequest(Object source, EventArgs e)
{
HttpContext context = ((HttpApplication)source).Context;
// Do something with context near the end of request processing.
}
}
}
Como se muestra en la página Middleware, un middleware ASP.NET Core es una clase que expone un método que toma y Invoke devuelve HttpContext Task . El nuevo middleware tendrá el siguiente aspecto:
// ASP.NET Core middleware
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace MyApp.Middleware
{
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
// Do something with context near the beginning of request processing.
await _next.Invoke(context);
// Clean up.
}
}
public static class MyMiddlewareExtensions
{
public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyMiddleware>();
}
}
}
La plantilla de middleware anterior se tomó de la sección sobre escritura de middleware.
La clase auxiliar MyMiddlewareExtensions facilita la configuración del middleware en la Startup clase. El UseMyMiddleware método agrega la clase de middleware a la canalización de solicitudes. Los servicios requeridos por el middleware se insertan en el constructor del middleware.
El módulo podría finalizar una solicitud, por ejemplo, si el usuario no está autorizado:
// ASP.NET 4 module that may terminate the request
private void Application_BeginRequest(Object source, EventArgs e)
{
HttpContext context = ((HttpApplication)source).Context;
// Do something with context near the beginning of request processing.
if (TerminateRequest())
{
context.Response.End();
return;
}
}
Un middleware controla esto sin llamar a Invoke en el siguiente middleware de la canalización. Tenga en cuenta que esto no finaliza completamente la solicitud, ya que los middleware anteriores se seguirán invocando cuando la respuesta vuelva a través de la canalización.
// ASP.NET Core middleware that may terminate the request
public async Task Invoke(HttpContext context)
{
// Do something with context near the beginning of request processing.
if (!TerminateRequest())
await _next.Invoke(context);
// Clean up.
}
Al migrar la funcionalidad del módulo al nuevo middleware, es posible que encuentre que el código no se compila porque la clase ha cambiado significativamente HttpContext en ASP.NET Core. Más adelanteen , verá cómo migrar a la nueva ASP.NET Core HttpContext.
Migración de la inserción de módulos en la canalización de solicitudes
Normalmente, los módulos HTTP se agregan a la canalización de solicitudes Web.config:
<?xml version="1.0" encoding="utf-8"?>
<!--ASP.NET 4 web.config-->
<configuration>
<system.webServer>
<modules>
<add name="MyModule" type="MyApp.Modules.MyModule"/>
</modules>
</system.webServer>
</configuration>
Para convertir esto, agregue el nuevo middleware a la canalización de solicitudes de la clase Startup :
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseMyMiddleware();
app.UseMyMiddlewareWithParams();
var myMiddlewareOptions = Configuration.GetSection("MyMiddlewareOptionsSection").Get<MyMiddlewareOptions>();
var myMiddlewareOptions2 = Configuration.GetSection("MyMiddlewareOptionsSection2").Get<MyMiddlewareOptions>();
app.UseMyMiddlewareWithParams(myMiddlewareOptions);
app.UseMyMiddlewareWithParams(myMiddlewareOptions2);
app.UseMyTerminatingMiddleware();
// Create branch to the MyHandlerMiddleware.
// All requests ending in .report will follow this branch.
app.MapWhen(
context => context.Request.Path.ToString().EndsWith(".report"),
appBranch => {
// ... optionally add more middleware to this branch
appBranch.UseMyHandler();
});
app.MapWhen(
context => context.Request.Path.ToString().EndsWith(".context"),
appBranch => {
appBranch.UseHttpContextDemoMiddleware();
});
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
La ubicación exacta en la canalización donde se inserta el nuevo middleware depende del evento que controló como un módulo ( BeginRequest , EndRequest , etc.) y su orden en la lista de módulos deWeb.config.
Como se indicó anteriormente, no hay ningún ciclo de vida de la aplicación en ASP.NET Core y el orden en que el middleware procesa las respuestas difiere del orden que usan los módulos. Esto podría hacer que la decisión de ordenación sea más difícil.
Si la ordenación se convierte en un problema, podría dividir el módulo en varios componentes de middleware que se pueden ordenar de forma independiente.
Migración de código de controlador a middleware
Un controlador HTTP tiene un aspecto similar al siguiente:
// ASP.NET 4 handler
using System.Web;
namespace MyApp.HttpHandlers
{
public class MyHandler : IHttpHandler
{
public bool IsReusable { get { return true; } }
public void ProcessRequest(HttpContext context)
{
string response = GenerateResponse(context);
context.Response.ContentType = GetContentType();
context.Response.Output.Write(response);
}
// ...
private string GenerateResponse(HttpContext context)
{
string title = context.Request.QueryString["title"];
return string.Format("Title of the report: {0}", title);
}
private string GetContentType()
{
return "text/plain";
}
}
}
En el ASP.NET Core proyecto, lo traduciría a un middleware similar al siguiente:
// ASP.NET Core middleware migrated from a handler
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace MyApp.Middleware
{
public class MyHandlerMiddleware
{
// Must have constructor with this signature, otherwise exception at run time
public MyHandlerMiddleware(RequestDelegate next)
{
// This is an HTTP Handler, so no need to store next
}
public async Task Invoke(HttpContext context)
{
string response = GenerateResponse(context);
context.Response.ContentType = GetContentType();
await context.Response.WriteAsync(response);
}
// ...
private string GenerateResponse(HttpContext context)
{
string title = context.Request.Query["title"];
return string.Format("Title of the report: {0}", title);
}
private string GetContentType()
{
return "text/plain";
}
}
public static class MyHandlerExtensions
{
public static IApplicationBuilder UseMyHandler(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyHandlerMiddleware>();
}
}
}
Este middleware es muy similar al middleware correspondiente a los módulos. La única diferencia real es que aquí no hay ninguna llamada a _next.Invoke(context) . Esto tiene sentido, porque el controlador está al final de la canalización de solicitud, por lo que no habrá ningún middleware siguiente que invocar.
Migración de la inserción del controlador en la canalización de solicitudes
La configuración de un controlador HTTP se realizaWeb.config y tiene un aspecto similar al siguiente:
<?xml version="1.0" encoding="utf-8"?>
<!--ASP.NET 4 web.config-->
<configuration>
<system.webServer>
<handlers>
<add name="MyHandler" verb="*" path="*.report" type="MyApp.HttpHandlers.MyHandler" resourceType="Unspecified" preCondition="integratedMode"/>
</handlers>
</system.webServer>
</configuration>
Puede convertir esto agregando el nuevo middleware de controlador a la canalización de solicitudes de la clase, de forma similar al Startup middleware convertido desde módulos. El problema con ese enfoque es que enviaría todas las solicitudes al nuevo middleware de controlador. Sin embargo, solo quiere que las solicitudes con una extensión determinada lleguen al middleware. Esto le proporcionaría la misma funcionalidad que tenía con el controlador HTTP.
Una solución consiste en bifurcar la canalización para las solicitudes con una extensión determinada, mediante el método MapWhen de extensión . Esto se hace en el mismo Configure método en el que se agrega el otro middleware:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseMyMiddleware();
app.UseMyMiddlewareWithParams();
var myMiddlewareOptions = Configuration.GetSection("MyMiddlewareOptionsSection").Get<MyMiddlewareOptions>();
var myMiddlewareOptions2 = Configuration.GetSection("MyMiddlewareOptionsSection2").Get<MyMiddlewareOptions>();
app.UseMyMiddlewareWithParams(myMiddlewareOptions);
app.UseMyMiddlewareWithParams(myMiddlewareOptions2);
app.UseMyTerminatingMiddleware();
// Create branch to the MyHandlerMiddleware.
// All requests ending in .report will follow this branch.
app.MapWhen(
context => context.Request.Path.ToString().EndsWith(".report"),
appBranch => {
// ... optionally add more middleware to this branch
appBranch.UseMyHandler();
});
app.MapWhen(
context => context.Request.Path.ToString().EndsWith(".context"),
appBranch => {
appBranch.UseHttpContextDemoMiddleware();
});
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
MapWhen toma estos parámetros:
Lambda que toma y
HttpContextdevuelve si la solicitud debe bajar por latruerama. Esto significa que puede bifurcar solicitudes no solo en función de su extensión, sino también en encabezados de solicitud, parámetros de cadena de consulta, etc.Lambda que toma y
IApplicationBuilderagrega todo el middleware para la rama. Esto significa que puede agregar middleware adicional a la rama delante del middleware del controlador.
Middleware agregado a la canalización antes de que se invoque la rama en todas las solicitudes; la rama no tendrá ningún impacto en ellos.
Carga de opciones de middleware mediante el patrón de opciones
Algunos módulos y controladores tienen opciones de configuración que se almacenan enWeb.config. Sin embargo, en ASP.NET Core se usa un nuevo modelo de configuración en lugar deWeb.config.
El nuevo sistema de configuración proporciona estas opciones para resolver esto:
Inserta directamente las opciones en el middleware, como se muestra en la sección siguiente.
Use el patrón de opciones:
Cree una clase para contener las opciones de middleware, por ejemplo:
public class MyMiddlewareOptions { public string Param1 { get; set; } public string Param2 { get; set; } }Almacenamiento de los valores de opción
El sistema de configuración permite almacenar valores de opción en cualquier lugar que desee. Sin embargo, la mayoría de los appsettings.json sitios usan , por lo que tomaremos ese enfoque:
{ "MyMiddlewareOptionsSection": { "Param1": "Param1Value", "Param2": "Param2Value" } }MyMiddlewareOptionsSection aquí es un nombre de sección. No tiene que ser el mismo que el nombre de la clase de opciones.
Asociación de los valores de opción a la clase options
El patrón de opciones usa ASP.NET Core marco de inserción de dependencias para asociar el tipo de opciones (como ) a un objeto
MyMiddlewareOptionsque tiene las opcionesMyMiddlewareOptionsreales.Actualice la
Startupclase:Si usa , appsettings.json agrégrelo al generador de configuración en el
Startupconstructor:public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); }Configure el servicio de opciones:
public void ConfigureServices(IServiceCollection services) { // Setup options service services.AddOptions(); // Load options from section "MyMiddlewareOptionsSection" services.Configure<MyMiddlewareOptions>( Configuration.GetSection("MyMiddlewareOptionsSection")); // Add framework services. services.AddMvc(); }Asocie las opciones a la clase de opciones:
public void ConfigureServices(IServiceCollection services) { // Setup options service services.AddOptions(); // Load options from section "MyMiddlewareOptionsSection" services.Configure<MyMiddlewareOptions>( Configuration.GetSection("MyMiddlewareOptionsSection")); // Add framework services. services.AddMvc(); }
Inserta las opciones en el constructor de middleware. Esto es similar a insertar opciones en un controlador.
public class MyMiddlewareWithParams { private readonly RequestDelegate _next; private readonly MyMiddlewareOptions _myMiddlewareOptions; public MyMiddlewareWithParams(RequestDelegate next, IOptions<MyMiddlewareOptions> optionsAccessor) { _next = next; _myMiddlewareOptions = optionsAccessor.Value; } public async Task Invoke(HttpContext context) { // Do something with context near the beginning of request processing // using configuration in _myMiddlewareOptions await _next.Invoke(context); // Do something with context near the end of request processing // using configuration in _myMiddlewareOptions } }El método de extensión UseMiddleware que agrega el middleware a se encarga de la
IApplicationBuilderinserción de dependencias.Esto no se limita a
IOptionslos objetos . Cualquier otro objeto que requiera el middleware se puede insertar de esta manera.
Carga de opciones de middleware mediante inserción directa
El patrón de opciones tiene la ventaja de que crea un acoplamiento flexible entre los valores de opciones y sus consumidores. Una vez que haya asociado una clase de opciones con los valores de opciones reales, cualquier otra clase puede obtener acceso a las opciones a través del marco de inserción de dependencias. No es necesario pasar valores de opciones.
Sin embargo, esto se interrumpe si desea usar el mismo middleware dos veces, con distintas opciones. Por ejemplo, un middleware de autorización que se usa en ramas diferentes que permiten roles diferentes. No se pueden asociar dos objetos de opciones diferentes a la clase de opciones.
La solución es obtener los objetos de opciones con los valores de opciones reales de la clase y pasar los objetos Startup directamente a cada instancia del middleware.
Agregar una segunda clave a appsettings.json
Para agregar un segundo conjunto de opciones al appsettings.json archivo, use una nueva clave para identificarlo de forma única:
{ "MyMiddlewareOptionsSection2": { "Param1": "Param1Value2", "Param2": "Param2Value2" }, "MyMiddlewareOptionsSection": { "Param1": "Param1Value", "Param2": "Param2Value" } }Recupere los valores de las opciones y pásenlos al middleware. El
Use...método de extensión (que agrega el middleware a la canalización) es un lugar lógico para pasar los valores de opción:public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseMyMiddleware(); app.UseMyMiddlewareWithParams(); var myMiddlewareOptions = Configuration.GetSection("MyMiddlewareOptionsSection").Get<MyMiddlewareOptions>(); var myMiddlewareOptions2 = Configuration.GetSection("MyMiddlewareOptionsSection2").Get<MyMiddlewareOptions>(); app.UseMyMiddlewareWithParams(myMiddlewareOptions); app.UseMyMiddlewareWithParams(myMiddlewareOptions2); app.UseMyTerminatingMiddleware(); // Create branch to the MyHandlerMiddleware. // All requests ending in .report will follow this branch. app.MapWhen( context => context.Request.Path.ToString().EndsWith(".report"), appBranch => { // ... optionally add more middleware to this branch appBranch.UseMyHandler(); }); app.MapWhen( context => context.Request.Path.ToString().EndsWith(".context"), appBranch => { appBranch.UseHttpContextDemoMiddleware(); }); app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }Habilite el middleware para tomar un parámetro de opciones. Proporcione una sobrecarga del método
Use...de extensión (que toma el parámetro options y lo pasa aUseMiddleware). Cuando se llama a con parámetros, pasa los parámetros al constructor de middleware cuando crea una instanciaUseMiddlewaredel objeto middleware.public static class MyMiddlewareWithParamsExtensions { public static IApplicationBuilder UseMyMiddlewareWithParams( this IApplicationBuilder builder) { return builder.UseMiddleware<MyMiddlewareWithParams>(); } public static IApplicationBuilder UseMyMiddlewareWithParams( this IApplicationBuilder builder, MyMiddlewareOptions myMiddlewareOptions) { return builder.UseMiddleware<MyMiddlewareWithParams>( new OptionsWrapper<MyMiddlewareOptions>(myMiddlewareOptions)); } }Observe cómo encapsula el objeto options en un
OptionsWrapperobjeto . Esto implementaIOptions, según lo esperado por el constructor de middleware.
Migración al nuevo HttpContext
Anteriormente ha visto que el Invoke método del middleware toma un parámetro de tipo HttpContext :
public async Task Invoke(HttpContext context)
HttpContextha cambiado significativamente en ASP.NET Core. En esta sección se muestra cómo traducir las propiedades más usadas de System.Web.HttpContext al nuevo Microsoft.AspNetCore.Http.HttpContext .
HttpContext
HttpContext.Items se traduce a:
IDictionary<object, object> items = httpContext.Items;
Identificador de solicitud único (sin homólogo de System.Web.HttpContext)
Proporciona un identificador único para cada solicitud. Muy útil para incluir en los registros.
string requestId = httpContext.TraceIdentifier;
HttpContext.Request
HttpContext.Request.HttpMethod se traduce a:
string httpMethod = httpContext.Request.Method;
HttpContext.Request.QueryString se traduce a:
IQueryCollection queryParameters = httpContext.Request.Query;
// If no query parameter "key" used, values will have 0 items
// If single value used for a key (...?key=v1), values will have 1 item ("v1")
// If key has multiple values (...?key=v1&key=v2), values will have 2 items ("v1" and "v2")
IList<string> values = queryParameters["key"];
// If no query parameter "key" used, value will be ""
// If single value used for a key (...?key=v1), value will be "v1"
// If key has multiple values (...?key=v1&key=v2), value will be "v1,v2"
string value = queryParameters["key"].ToString();
HttpContext.Request.Url y HttpContext.Request.RawUrl se traducen a:
// using Microsoft.AspNetCore.Http.Extensions;
var url = httpContext.Request.GetDisplayUrl();
HttpContext.Request.IsSecureConnection se traduce a:
var isSecureConnection = httpContext.Request.IsHttps;
HttpContext.Request.UserHostAddress se traduce a:
var userHostAddress = httpContext.Connection.RemoteIpAddress?.ToString();
HttpContext.Request. Cookie s se traduce a:
IRequestCookieCollection cookies = httpContext.Request.Cookies;
string unknownCookieValue = cookies["unknownCookie"]; // will be null (no exception)
string knownCookieValue = cookies["cookie1name"]; // will be actual value
HttpContext.Request.RequestContext.RouteData se traduce a:
var routeValue = httpContext.GetRouteValue("key");
HttpContext.Request.Headers se traduce a:
// using Microsoft.AspNetCore.Http.Headers;
// using Microsoft.Net.Http.Headers;
IHeaderDictionary headersDictionary = httpContext.Request.Headers;
// GetTypedHeaders extension method provides strongly typed access to many headers
var requestHeaders = httpContext.Request.GetTypedHeaders();
CacheControlHeaderValue cacheControlHeaderValue = requestHeaders.CacheControl;
// For unknown header, unknownheaderValues has zero items and unknownheaderValue is ""
IList<string> unknownheaderValues = headersDictionary["unknownheader"];
string unknownheaderValue = headersDictionary["unknownheader"].ToString();
// For known header, knownheaderValues has 1 item and knownheaderValue is the value
IList<string> knownheaderValues = headersDictionary[HeaderNames.AcceptLanguage];
string knownheaderValue = headersDictionary[HeaderNames.AcceptLanguage].ToString();
HttpContext.Request.UserAgent se traduce a:
string userAgent = headersDictionary[HeaderNames.UserAgent].ToString();
HttpContext.Request.UrlReferrer se traduce a:
string urlReferrer = headersDictionary[HeaderNames.Referer].ToString();
HttpContext.Request.ContentType se traduce a:
// using Microsoft.Net.Http.Headers;
MediaTypeHeaderValue mediaHeaderValue = requestHeaders.ContentType;
string contentType = mediaHeaderValue?.MediaType.ToString(); // ex. application/x-www-form-urlencoded
string contentMainType = mediaHeaderValue?.Type.ToString(); // ex. application
string contentSubType = mediaHeaderValue?.SubType.ToString(); // ex. x-www-form-urlencoded
System.Text.Encoding requestEncoding = mediaHeaderValue?.Encoding;
HttpContext.Request.Form se traduce a:
if (httpContext.Request.HasFormContentType)
{
IFormCollection form;
form = httpContext.Request.Form; // sync
// Or
form = await httpContext.Request.ReadFormAsync(); // async
string firstName = form["firstname"];
string lastName = form["lastname"];
}
Advertencia
Lea los valores de formulario solo si el subtipo de contenido es x-www-form-urlencoded o form-data.
HttpContext.Request.InputStream se traduce a:
string inputBody;
using (var reader = new System.IO.StreamReader(
httpContext.Request.Body, System.Text.Encoding.UTF8))
{
inputBody = reader.ReadToEnd();
}
Advertencia
Use este código solo en un middleware de tipo controlador, al final de una canalización.
Puede leer el cuerpo sin formato como se muestra anteriormente solo una vez por solicitud. El middleware que intenta leer el cuerpo después de la primera lectura leerá un cuerpo vacío.
Esto no se aplica a la lectura de un formulario como se mostró anteriormente, porque se hace desde un búfer.
HttpContext.Response
HttpContext.Response.Status y HttpContext.Response.StatusDescription se traducen a:
// using Microsoft.AspNetCore.Http;
httpContext.Response.StatusCode = StatusCodes.Status200OK;
HttpContext.Response.ContentEncoding y HttpContext.Response.ContentType se traducen a:
// using Microsoft.Net.Http.Headers;
var mediaType = new MediaTypeHeaderValue("application/json");
mediaType.Encoding = System.Text.Encoding.UTF8;
httpContext.Response.ContentType = mediaType.ToString();
HttpContext.Response.ContentType por sí solo también se traduce en:
httpContext.Response.ContentType = "text/html";
HttpContext.Response.Output se traduce a:
string responseContent = GetResponseContent();
await httpContext.Response.WriteAsync(responseContent);
HttpContext.Response.TransmitFile
El servicio de un archivo se describe en Características de solicitud de ASP.NET Core .
HttpContext.Response.Headers
El envío de encabezados de respuesta es complicado por el hecho de que, si los establece después de escribir algo en el cuerpo de la respuesta, no se enviarán.
La solución consiste en establecer un método de devolución de llamada al que se llamará justo antes de que se inicie la escritura en la respuesta. Esto se hace mejor al principio del método Invoke en el middleware. Es este método de devolución de llamada el que establece los encabezados de respuesta.
El código siguiente establece un método de devolución de llamada denominado SetHeaders :
public async Task Invoke(HttpContext httpContext)
{
// ...
httpContext.Response.OnStarting(SetHeaders, state: httpContext);
El SetHeaders método de devolución de llamada tendría el siguiente aspecto:
// using Microsoft.AspNet.Http.Headers;
// using Microsoft.Net.Http.Headers;
private Task SetHeaders(object context)
{
var httpContext = (HttpContext)context;
// Set header with single value
httpContext.Response.Headers["ResponseHeaderName"] = "headerValue";
// Set header with multiple values
string[] responseHeaderValues = new string[] { "headerValue1", "headerValue1" };
httpContext.Response.Headers["ResponseHeaderName"] = responseHeaderValues;
// Translating ASP.NET 4's HttpContext.Response.RedirectLocation
httpContext.Response.Headers[HeaderNames.Location] = "http://www.example.com";
// Or
httpContext.Response.Redirect("http://www.example.com");
// GetTypedHeaders extension method provides strongly typed access to many headers
var responseHeaders = httpContext.Response.GetTypedHeaders();
// Translating ASP.NET 4's HttpContext.Response.CacheControl
responseHeaders.CacheControl = new CacheControlHeaderValue
{
MaxAge = new System.TimeSpan(365, 0, 0, 0)
// Many more properties available
};
// If you use .NET Framework 4.6+, Task.CompletedTask will be a bit faster
return Task.FromResult(0);
}
HttpContext.Response. Cookie s
Cookiese desplazan al explorador en un encabezado de respuesta Cookie Set-. Como resultado, el envío cookie de s requiere la misma devolución de llamada que se usa para enviar encabezados de respuesta:
public async Task Invoke(HttpContext httpContext)
{
// ...
httpContext.Response.OnStarting(SetCookies, state: httpContext);
httpContext.Response.OnStarting(SetHeaders, state: httpContext);
El SetCookies método de devolución de llamada tendría un aspecto parecido al siguiente:
private Task SetCookies(object context)
{
var httpContext = (HttpContext)context;
IResponseCookies responseCookies = httpContext.Response.Cookies;
responseCookies.Append("cookie1name", "cookie1value");
responseCookies.Append("cookie2name", "cookie2value",
new CookieOptions { Expires = System.DateTime.Now.AddDays(5), HttpOnly = true });
// If you use .NET Framework 4.6+, Task.CompletedTask will be a bit faster
return Task.FromResult(0);
}