Migrace modulů a obslužných rutin HTTP do middlewaru ASP.NET Core
Tento článek ukazuje, jak migrovat existující ASP.NET moduly HTTP a obslužné rutiny ze system.webserveru do middlewaru ASP.NET Core.
Moduly a obslužné rutiny se znovu zobrazí
Než se pustíme do ASP.NET middlewaru Core, pojďme nejprve zrekapitulovat, jak fungují moduly HTTP a obslužné rutiny:
Obslužné rutiny jsou:
Třídy, které implementují IHttpHandler
Používá se ke zpracování požadavků s daným názvem souboru nebo příponou, například .report.
Nakonfigurováno v souboru Web.config
Moduly jsou:
Třídy, které implementují IHttpModule
Vyvoláno pro každý požadavek
Možnost zkratování (zastavení dalšího zpracování žádosti)
Možnost přidat do odpovědi HTTP nebo vytvořit vlastní
Nakonfigurováno v souboru Web.config
Pořadí, ve kterém moduly zpracovávají příchozí požadavky, určuje:
Události řady aktivované ASP.NET, například BeginRequest a AuthenticateRequest. Úplný seznam najdete v tématu System.Web.HttpApplication. Každý modul může vytvořit obslužnou rutinu pro jednu nebo více událostí.
U stejné události je pořadí, ve kterém jsou nakonfigurované v souboru Web.config.
Kromě modulů můžete do Global.asax.cs
souboru přidat obslužné rutiny pro události životního cyklu. Tyto obslužné rutiny se spouští po obslužných rutinách v nakonfigurovaných modulech.
Od obslužných rutin a modulů po middleware
Middleware je jednodušší než moduly a obslužné rutiny HTTP:
Moduly, obslužné rutiny,
Global.asax.cs
Web.config (s výjimkou konfigurace služby IIS) a životní cyklus aplikace jsou pryč.Role modulů a obslužných rutin převzal middleware.
Middleware se konfiguruje pomocí kódu místo v souboru Web.config.
- Větvení kanálů umožňuje odesílat požadavky do konkrétního middlewaru, a to na základě adresy URL, ale také hlaviček požadavků, řetězců dotazů atd.
- Větvení kanálů umožňuje odesílat požadavky do konkrétního middlewaru, a to na základě adresy URL, ale také hlaviček požadavků, řetězců dotazů atd.
Middleware je velmi podobný modulům:
Vyvolána v zásadě pro každou žádost
Možnost zkratovat požadavek tím, že požadavek nepředáte do dalšího middlewaru
Možnost vytvořit vlastní odpověď HTTP
Middleware a moduly se zpracovávají v jiném pořadí:
Pořadí middlewaru je založené na pořadí, ve kterém jsou vloženy do kanálu požadavku, zatímco pořadí modulů je založené hlavně na System.Web.HttpApplication událostech.
Pořadí middlewaru pro odpovědi je opačné než u požadavků, zatímco pořadí modulů je stejné pro požadavky a odpovědi.
Viz Vytvoření kanálu middlewaru pomocí nástroje IApplicationBuilder
Všimněte si, jak na obrázku výše se požadavek zkrátil na ověřovacím middlewaru.
Migrace kódu modulu do middlewaru
Existující modul HTTP bude vypadat nějak takto:
// 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.
}
}
}
Jak je znázorněno na stránce Middleware, middleware ASP.NET Core je třída, která zveřejňuje metodu Invoke
HttpContext
Task
, která přebírá a vrací . Váš nový middleware bude vypadat takto:
// 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>();
}
}
}
Předchozí šablona middlewaru byla převzata z části věnované psaní middlewaru.
Pomocná třída MyMiddlewareExtensions usnadňuje konfiguraci middlewaru ve třídě Startup
. Metoda UseMyMiddleware
přidá třídu middlewaru do kanálu požadavku. Služby vyžadované middlewarem se vloží do konstruktoru middlewaru.
Váš modul může žádost ukončit, například pokud uživatel nemá oprávnění:
// 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;
}
}
Middleware to zpracovává tak, že nevolá Invoke
další middleware v kanálu. Mějte na paměti, že se tím požadavek úplně neukončí, protože předchozí middlewary budou stále vyvolány, když odpověď provede cestu zpět v kanálu.
// 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.
}
Když migrujete funkce modulu do nového middlewaru, můžete zjistit, že se váš kód nekompiluje, protože HttpContext
se třída výrazně změnila v ASP.NET Core. Později se dozvíte, jak migrovat na nový ASP.NET Core HttpContext.
Migrace modulu vložení do kanálu žádosti
Moduly HTTP se obvykle přidávají do kanálu požadavku pomocí 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>
Převeďte ho přidáním nového middlewaru do kanálu požadavku ve třídě 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?}");
});
}
Přesné místo v kanálu, kam vkládáte nový middleware, závisí na události, kterou zpracovává jako modul (BeginRequest
atd EndRequest
.) a jeho pořadí v seznamu modulů v souboru Web.config.
Jak jsme uvedli dříve, v ASP.NET Core neexistuje žádný životní cyklus aplikace a pořadí, ve kterém se odpovědi zpracovávají middlewarem, se liší od pořadí používaného moduly. To by mohlo znamenat, že vaše rozhodnutí o objednávání bude náročnější.
Pokud se řazení stane problémem, můžete modul rozdělit na několik komponent middlewaru, které je možné objednat nezávisle.
Migrace kódu obslužné rutiny do middlewaru
Obslužná rutina HTTP vypadá přibližně takto:
// 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";
}
}
}
V projektu ASP.NET Core byste to přeložili do middlewaru podobnému tomuto:
// 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>();
}
}
}
Tento middleware je velmi podobný middlewaru odpovídajícím modulům. Jediným skutečným rozdílem je, že tady není žádné volání _next.Invoke(context)
. To dává smysl, protože obslužná rutina je na konci kanálu požadavku, takže nebude k dispozici žádný další middleware k vyvolání.
Migrace vložení obslužné rutiny do kanálu požadavku
Konfigurace obslužné rutiny HTTP se provádí v souboru Web.config a vypadá nějak takto:
<?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>
Můžete to převést přidáním nového middlewaru obslužné rutiny do kanálu požadavku ve vaší Startup
třídě, podobně jako middleware převedený z modulů. Problém s tímto přístupem spočívá v tom, že by odeslal všechny požadavky do vašeho nového middlewaru obslužné rutiny. Chcete ale, aby se požadavky s daným rozšířením dostaly do vašeho middlewaru. To by vám poskytlo stejné funkce jako u obslužné rutiny HTTP.
Jedním z řešení je větvení kanálu pro požadavky s daným rozšířením pomocí MapWhen
metody rozšíření. Provedete to ve stejné Configure
metodě, ve které přidáte druhý 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
přebírá tyto parametry:
Lambda, která vezme
HttpContext
a vrátítrue
, pokud má požadavek přejít dolů do větve. To znamená, že žádosti můžete rozvětvovat nejen na základě jejich rozšíření, ale také na hlavičkách požadavků, parametrech řetězce dotazu atd.Lambda, která vezme
IApplicationBuilder
a přidá veškerý middleware pro větev. To znamená, že do větve před middleware obslužné rutiny můžete přidat další middleware.
Middleware přidaný do kanálu před vyvolání větve pro všechny požadavky; větev nebude mít na ně žádný vliv.
Načítání možností middlewaru pomocí vzoru možností
Některé moduly a obslužné rutiny mají možnosti konfigurace uložené v souboru Web.config. V ASP.NET Core se ale místo Web.config používá nový konfigurační model.
Nový konfigurační systém nabízí tyto možnosti řešení:
Přímo vložte možnosti do middlewaru, jak je znázorněno v další části.
Použijte vzor možností:
Vytvořte třídu pro uložení možností middlewaru, například:
public class MyMiddlewareOptions { public string Param1 { get; set; } public string Param2 { get; set; } }
Uložení hodnot možností
Konfigurační systém umožňuje ukládat hodnoty možností kdekoli, kde chcete. Většina webů ale používá
appsettings.json
tento přístup:{ "MyMiddlewareOptionsSection": { "Param1": "Param1Value", "Param2": "Param2Value" } }
MyMiddlewareOptionsSection je název oddílu. Nemusí se shodovat s názvem třídy možností.
Přidružení hodnot možností ke třídě options
Model možností používá architekturu injektáže závislostí ASP.NET Core k přidružení typu možností (například
MyMiddlewareOptions
) kMyMiddlewareOptions
objektu, který má skutečné možnosti.Aktualizujte předmět
Startup
:Pokud používáte
appsettings.json
, přidejte ho do tvůrce konfigurace v konstruktoruStartup
: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(); }
Nakonfigurujte službu možností:
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(); }
Přidružte možnosti ke třídě možností:
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(); }
Vložte možnosti do konstruktoru middlewaru. Podobá se vkládání možností do kontroleru.
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 } }
Metoda rozšíření UseMiddleware , která přidává váš middleware k
IApplicationBuilder
péči o injektáž závislostí.To není omezeno na
IOptions
objekty. Jakýkoli jiný objekt, který middleware vyžaduje, je možné tímto způsobem vloženého.
Načítání možností middlewaru prostřednictvím přímé injektáže
Vzor možností má výhodu, že vytváří volné spojení mezi hodnotami možností a jejich spotřebiteli. Jakmile přidružíte třídu možností se skutečnými hodnotami možností, může každá jiná třída získat přístup k možnostem prostřednictvím architektury injektáže závislostí. Není potřeba předávat hodnoty možností.
To se ale rozdělí, pokud chcete použít stejný middleware dvakrát, s různými možnostmi. Například autorizační middleware používaný v různých větvích, které umožňují různé role. Nelze přidružit dva různé objekty možností k jedné třídě možností.
Řešením je získat objekty možností se skutečnými hodnotami možností ve vaší Startup
třídě a předat je přímo do každé instance middlewaru.
Přidání druhého klíče do
appsettings.json
Pokud chcete do
appsettings.json
souboru přidat druhou sadu možností, použijte k jedinečné identifikaci nový klíč:{ "MyMiddlewareOptionsSection2": { "Param1": "Param1Value2", "Param2": "Param2Value2" }, "MyMiddlewareOptionsSection": { "Param1": "Param1Value", "Param2": "Param2Value" } }
Načtěte hodnoty možností a předejte je middlewaru. Metoda
Use...
rozšíření (která přidává váš middleware do kanálu) je logické místo pro předávání hodnot možností: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?}"); }); }
Povolte middleware, abyste mohli použít parametr možností. Zadejte přetížení
Use...
rozšiřující metody (která přebírá parametr možností a předává hoUseMiddleware
). PřiUseMiddleware
zavolání s parametry předá parametry konstruktoru middlewaru při vytvoření instance middlewarového objektu.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)); } }
Všimněte si, jak se tím zalomí objekt možností v objektu
OptionsWrapper
. Tím se implementujeIOptions
, podle očekávání middlewarový konstruktor.
Migrace na nový httpContext
Viděli jste dříve, že Invoke
metoda v middlewaru přebírá parametr typu HttpContext
:
public async Task Invoke(HttpContext context)
HttpContext
výrazně se změnila v ASP.NET Core. Tato část ukazuje, jak přeložit nejčastěji používané vlastnosti System.Web.HttpContext na nový Microsoft.AspNetCore.Http.HttpContext
.
HttpContext
HttpContext.Items se překládá na:
IDictionary<object, object> items = httpContext.Items;
Jedinečné ID požadavku (bez system.Web.HttpContext protějšek)
Poskytuje jedinečné ID pro každý požadavek. Velmi užitečné zahrnout do protokolů.
string requestId = httpContext.TraceIdentifier;
HttpContext.Request
HttpContext.Request.HttpMethod se překládá na:
string httpMethod = httpContext.Request.Method;
HttpContext.Request.QueryString se překládá na:
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 a HttpContext.Request.RawUrl přeloží na:
// using Microsoft.AspNetCore.Http.Extensions;
var url = httpContext.Request.GetDisplayUrl();
HttpContext.Request.IsSecureConnection se překládá na:
var isSecureConnection = httpContext.Request.IsHttps;
HttpContext.Request.UserHostAddress se překládá na:
var userHostAddress = httpContext.Connection.RemoteIpAddress?.ToString();
HttpContext.Request.Cookies se překládá na:
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 překládá na:
var routeValue = httpContext.GetRouteValue("key");
HttpContext.Request.Headers se překládá na:
// 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 překládá na:
string userAgent = headersDictionary[HeaderNames.UserAgent].ToString();
HttpContext.Request.UrlReferrer se překládá na:
string urlReferrer = headersDictionary[HeaderNames.Referer].ToString();
HttpContext.Request.ContentType se překládá na:
// 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 překládá na:
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"];
}
Upozorňující
Hodnoty formuláře se čtou jenom v případě, že je podtyp obsahu x-www-form-urlencoded nebo form-data.
HttpContext.Request.InputStream se překládá na:
string inputBody;
using (var reader = new System.IO.StreamReader(
httpContext.Request.Body, System.Text.Encoding.UTF8))
{
inputBody = reader.ReadToEnd();
}
Upozorňující
Tento kód použijte pouze v middlewaru typu obslužné rutiny na konci kanálu.
Nezpracovaný text si můžete přečíst, jak je znázorněno výše, jenom jednou na požadavek. Middleware, který se pokusí přečíst tělo po prvním přečtení, přečte prázdné tělo.
To neplatí pro čtení formuláře, jak je znázorněno výše, protože to se provádí z vyrovnávací paměti.
HttpContext.Response
HttpContext.Response.Status a HttpContext.Response.StatusDescription se přeloží na:
// using Microsoft.AspNetCore.Http;
httpContext.Response.StatusCode = StatusCodes.Status200OK;
HttpContext.Response.ContentEncoding a HttpContext.Response.ContentType se přeloží na:
// 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 samostatně také překládá na:
httpContext.Response.ContentType = "text/html";
HttpContext.Response.Output se překládá na:
string responseContent = GetResponseContent();
await httpContext.Response.WriteAsync(responseContent);
HttpContext.Response.TransmitFile
Obsluha souboru je popsána v části Funkce žádosti v ASP.NET Core.
HttpContext.Response.Headers
Odesílání hlaviček odpovědí je složité tím, že pokud je nastavíte po napsání čehokoli do textu odpovědi, neodesílají se.
Řešením je nastavit metodu zpětného volání, která bude volána přímo před zápisem do odpovědi. To se nejlépe provádí na začátku metody v middlewaru Invoke
. Je to tato metoda zpětného volání, která nastavuje hlavičky odpovědi.
Následující kód nastaví metodu zpětného volání s názvem SetHeaders
:
public async Task Invoke(HttpContext httpContext)
{
// ...
httpContext.Response.OnStarting(SetHeaders, state: httpContext);
SetHeaders
Metoda zpětného volání by vypadala takto:
// 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.Cookies
Soubory cookie putují do prohlížeče v hlavičce set-responseCookie . V důsledku toho odesílání souborů cookie vyžaduje stejné zpětné volání jako při odesílání hlaviček odpovědi:
public async Task Invoke(HttpContext httpContext)
{
// ...
httpContext.Response.OnStarting(SetCookies, state: httpContext);
httpContext.Response.OnStarting(SetHeaders, state: httpContext);
SetCookies
Metoda zpětného volání by vypadala takto:
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);
}