Migrowanie modułów i programów obsługi HTTP do oprogramowania pośredniczącego platformy ASP.NET Core
W tym artykule pokazano, jak przeprowadzić migrację istniejących modułów HTTP ASP.NET i procedur obsługi z pliku system.webserver do oprogramowania pośredniczącego ASP.NET Core.
Ponownie przeglądane moduły i programy obsługi
Przed przejściem do oprogramowania pośredniczącego ASP.NET Core najpierw podsumujmy, jak działają moduły HTTP i programy obsługi:
Programy obsługi to:
Klasy implementujące IHttpHandler
Służy do obsługi żądań z daną nazwą pliku lub rozszerzeniem, takim jak .report
Skonfigurowane w pliku Web.config
Moduły to:
Klasy implementujące IHttpModule
Wywoływane dla każdego żądania
Możliwość zwarć (zatrzymać dalsze przetwarzanie żądania)
Możliwość dodania do odpowiedzi HTTP lub utworzenia własnej
Skonfigurowane w pliku Web.config
Kolejność przetwarzania żądań przychodzących przez moduły jest określana przez:
Zdarzenia serii wyzwalane przez ASP.NET, takie jak BeginRequest i AuthenticateRequest. Aby uzyskać pełną listę, zobacz System.Web.HttpApplication. Każdy moduł może utworzyć procedurę obsługi dla co najmniej jednego zdarzenia.
W przypadku tego samego zdarzenia kolejność, w której są one skonfigurowane w pliku Web.config.
Oprócz modułów można dodawać programy obsługi zdarzeń cyklu życia do pliku Global.asax.cs
. Te programy obsługi są uruchamiane po programach obsługi w skonfigurowanych modułach.
Od programów obsługi i modułów po oprogramowanie pośredniczące
Oprogramowanie pośredniczące jest prostsze niż moduły HTTP i programy obsługi:
Moduły, programy obsługi,
Global.asax.cs
, Web.config (z wyjątkiem konfiguracji usług IIS) i cykl życia aplikacji zniknąRole modułów i programów obsługi zostały przejęte przez oprogramowanie pośredniczące
Oprogramowanie pośredniczące jest konfigurowane przy użyciu kodu, a nie w pliku Web.config
- Rozgałęzianie potoku umożliwia wysyłanie żądań do określonego oprogramowania pośredniczącego na podstawie nie tylko adresu URL, ale także nagłówków żądań, ciągów zapytania itp.
- Rozgałęzianie potoku umożliwia wysyłanie żądań do określonego oprogramowania pośredniczącego na podstawie nie tylko adresu URL, ale także nagłówków żądań, ciągów zapytania itp.
Oprogramowanie pośredniczące jest bardzo podobne do modułów:
Wywoływane w zasadzie dla każdego żądania
Możliwość zwarć żądania, nie przekazując żądania do następnego oprogramowania pośredniczącego
Możliwość utworzenia własnej odpowiedzi HTTP
Oprogramowanie pośredniczące i moduły są przetwarzane w innej kolejności:
Kolejność oprogramowania pośredniczącego jest oparta na kolejności, w jakiej są one wstawiane do potoku żądania, podczas gdy kolejność modułów jest oparta głównie na System.Web.HttpApplication zdarzeniach.
Kolejność oprogramowania pośredniczącego dla odpowiedzi jest odwrotna od tego dla żądań, natomiast kolejność modułów jest taka sama w przypadku żądań i odpowiedzi
Zobacz Tworzenie potoku oprogramowania pośredniczącego za pomocą interfejsu IApplicationBuilder
Zwróć uwagę, jak na powyższym obrazie oprogramowanie pośredniczące uwierzytelniania zwarło żądanie.
Migrowanie kodu modułu do oprogramowania pośredniczącego
Istniejący moduł HTTP będzie wyglądać podobnie do następującego:
// 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 pokazano na stronie Oprogramowanie pośredniczące , oprogramowanie pośredniczące ASP.NET Core jest klasą, która uwidacznia metodę Invoke
przyjmującą HttpContext
metodę i zwracającą element Task
. Nowe oprogramowanie pośredniczące będzie wyglądać następująco:
// 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>();
}
}
}
Powyższy szablon oprogramowania pośredniczącego został pobrany z sekcji dotyczącej pisania oprogramowania pośredniczącego.
Klasa pomocnika MyMiddlewareExtensions ułatwia konfigurowanie oprogramowania pośredniczącego w Startup
klasie. Metoda UseMyMiddleware
dodaje klasę oprogramowania pośredniczącego do potoku żądania. Usługi wymagane przez oprogramowanie pośredniczące są wstrzykiwane w konstruktorze oprogramowania pośredniczącego.
Moduł może zakończyć żądanie, na przykład jeśli użytkownik nie jest autoryzowany:
// 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;
}
}
Oprogramowanie pośredniczące obsługuje to, nie wywołując Invoke
następnego oprogramowania pośredniczącego w potoku. Należy pamiętać, że nie powoduje to całkowitego zakończenia żądania, ponieważ poprzednie oprogramowanie pośredniczące nadal będzie wywoływane, gdy odpowiedź wraca przez potok.
// 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.
}
Podczas migracji funkcji modułu do nowego oprogramowania pośredniczącego może się okazać, że kod nie zostanie skompilowany, ponieważ HttpContext
klasa uległa znacznej zmianie w ASP.NET Core. Później zobaczysz, jak przeprowadzić migrację do nowej ASP.NET Core HttpContext.
Migrowanie wstawiania modułu do potoku żądania
Moduły HTTP są zwykle dodawane do potoku żądań przy użyciu pliku 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>
Przekonwertuj to, dodając nowe oprogramowanie pośredniczące do potoku żądań w Startup
klasie:
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?}");
});
}
Dokładne miejsce w potoku, w którym wstawiasz nowe oprogramowanie pośredniczące, zależy od zdarzenia obsługiwanego jako moduł (BeginRequest
, EndRequest
itp.) i jego kolejności na liście modułów w pliku Web.config.
Jak wspomniano wcześniej, w ASP.NET Core nie ma cyklu życia aplikacji i kolejność przetwarzania odpowiedzi przez oprogramowanie pośredniczące różni się od kolejności używanej przez moduły. Może to sprawić, że decyzja o zamówieniu będzie trudniejsza.
Jeśli kolejność stanie się problemem, moduł można podzielić na wiele składników oprogramowania pośredniczącego, które mogą być uporządkowane niezależnie.
Migrowanie kodu procedury obsługi do oprogramowania pośredniczącego
Procedura obsługi HTTP wygląda następująco:
// 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";
}
}
}
W projekcie ASP.NET Core przetłumacz to na oprogramowanie pośredniczące podobne do następującego:
// 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>();
}
}
}
To oprogramowanie pośredniczące jest bardzo podobne do oprogramowania pośredniczącego odpowiadającego modułom. Jedyną prawdziwą różnicą jest to, że tutaj nie ma wywołania metody _next.Invoke(context)
. Ma to sens, ponieważ program obsługi znajduje się na końcu potoku żądania, więc nie będzie następnego oprogramowania pośredniczącego do wywołania.
Migrowanie wstawiania programu obsługi do potoku żądania
Konfigurowanie programu obsługi HTTP odbywa się w pliku Web.config i wygląda następująco:
<?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>
Możesz to przekonwertować, dodając nowe oprogramowanie pośredniczące programu obsługi do potoku żądania w Startup
klasie, podobnie jak oprogramowanie pośredniczące przekonwertowane z modułów. Problem z tym podejściem polega na tym, że będzie wysyłać wszystkie żądania do nowego oprogramowania pośredniczącego obsługi. Jednak chcesz, aby żądania z danym rozszerzeniem dotarły do oprogramowania pośredniczącego. Zapewnia to taką samą funkcjonalność, jaką miał program obsługi HTTP.
Jednym z rozwiązań jest rozgałęzienie potoku dla żądań z danym rozszerzeniem przy użyciu MapWhen
metody rozszerzenia. Można to zrobić w tej samej Configure
metodzie, w której dodajesz inne oprogramowanie pośredniczące:
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
przyjmuje następujące parametry:
Lambda, która pobiera
HttpContext
element i zwracatrue
, jeśli żądanie powinno przejść w dół gałęzi. Oznacza to, że można rozgałęzić żądania nie tylko na podstawie ich rozszerzenia, ale także nagłówków żądań, parametrów ciągu zapytania itp.Lambda, która przyjmuje element
IApplicationBuilder
i dodaje całe oprogramowanie pośredniczące dla gałęzi. Oznacza to, że można dodać dodatkowe oprogramowanie pośredniczące do gałęzi przed oprogramowaniem pośredniczącym programu obsługi.
Oprogramowanie pośredniczące dodane do potoku przed wywołaniem gałęzi we wszystkich żądaniach; gałąź nie będzie miała na nie wpływu.
Ładowanie opcji oprogramowania pośredniczącego przy użyciu wzorca opcji
Niektóre moduły i programy obsługi mają opcje konfiguracji przechowywane w pliku Web.config. Jednak w ASP.NET Core nowy model konfiguracji jest używany zamiast pliku Web.config.
Nowy system konfiguracji udostępnia następujące opcje:
Bezpośrednie wstrzykiwanie opcji do oprogramowania pośredniczącego, jak pokazano w następnej sekcji.
Użyj wzorca opcji:
Utwórz klasę do przechowywania opcji oprogramowania pośredniczącego, na przykład:
public class MyMiddlewareOptions { public string Param1 { get; set; } public string Param2 { get; set; } }
Przechowywanie wartości opcji
System konfiguracji umożliwia przechowywanie wartości opcji w dowolnym miejscu. Jednak większość witryn używa metody
appsettings.json
, więc zastosujemy takie podejście:{ "MyMiddlewareOptionsSection": { "Param1": "Param1Value", "Param2": "Param2Value" } }
MyMiddlewareOptionsSection tutaj jest nazwą sekcji. Nie musi być taka sama jak nazwa klasy opcji.
Kojarzenie wartości opcji z klasą options
Wzorzec opcji używa platformy iniekcji zależności ASP.NET Core do skojarzenia typu opcji (takiego jak
MyMiddlewareOptions
) z obiektemMyMiddlewareOptions
, który ma rzeczywiste opcje.Zaktualizuj klasę
Startup
:Jeśli używasz polecenia
appsettings.json
, dodaj go do konstruktora konfiguracji w konstruktorzeStartup
: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(); }
Skonfiguruj usługę opcji:
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(); }
Skojarz opcje z klasą opcji:
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(); }
Wstrzykiwanie opcji do konstruktora oprogramowania pośredniczącego. Jest to podobne do wstrzykiwania opcji do kontrolera.
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 rozszerzenia UseMiddleware, która dodaje oprogramowanie pośredniczące do
IApplicationBuilder
iniekcji zależności.Nie jest to ograniczone do
IOptions
obiektów. Każdy inny obiekt, którego wymaga oprogramowanie pośredniczące, można w ten sposób wstrzyknąć.
Ładowanie opcji oprogramowania pośredniczącego poprzez bezpośrednie wstrzyknięcie
Wzorzec opcji ma zaletę, że tworzy luźne sprzężenie między wartościami opcji a ich odbiorcami. Po skojarzeniu klasy options z rzeczywistymi wartościami opcji każda inna klasa może uzyskać dostęp do opcji za pośrednictwem struktury wstrzykiwania zależności. Nie ma potrzeby przekazywania wartości opcji.
Spowoduje to awarię, jeśli chcesz użyć tego samego oprogramowania pośredniczącego dwa razy, z różnymi opcjami. Na przykład oprogramowanie pośredniczące autoryzacji używane w różnych gałęziach zezwalających na różne role. Nie można skojarzyć dwóch różnych obiektów opcji z jedną klasą opcji.
Rozwiązaniem jest pobranie obiektów opcji z rzeczywistymi wartościami opcji w Startup
klasie i przekazanie ich bezpośrednio do każdego wystąpienia oprogramowania pośredniczącego.
Dodawanie drugiego klucza do
appsettings.json
Aby dodać drugi zestaw opcji do
appsettings.json
pliku, użyj nowego klucza, aby go jednoznacznie zidentyfikować:{ "MyMiddlewareOptionsSection2": { "Param1": "Param1Value2", "Param2": "Param2Value2" }, "MyMiddlewareOptionsSection": { "Param1": "Param1Value", "Param2": "Param2Value" } }
Pobierz wartości opcji i przekaż je do oprogramowania pośredniczącego.
Use...
Metoda rozszerzenia (która dodaje oprogramowanie pośredniczące do potoku) jest logicznym miejscem do przekazania wartości opcji: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?}"); }); }
Włącz oprogramowanie pośredniczące, aby pobrać parametr opcji. Podaj przeciążenie
Use...
metody rozszerzenia (która pobiera parametr options i przekazuje go do metodyUseMiddleware
). GdyUseMiddleware
jest wywoływany z parametrami, przekazuje parametry do konstruktora oprogramowania pośredniczącego podczas tworzenia wystąpienia obiektu oprogramowania pośredniczącego.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)); } }
Zwróć uwagę, jak to opakowuje obiekt options w
OptionsWrapper
obiekcie. Spowoduje to zaimplementowanieIOptions
metody , zgodnie z oczekiwaniami przez konstruktor oprogramowania pośredniczącego.
Migrowanie do nowego obiektu HttpContext
Pokazano wcześniej, że metoda w narzędziu Invoke
pośredniczącym przyjmuje parametr typu HttpContext
:
public async Task Invoke(HttpContext context)
HttpContext
znacznie się zmienił w ASP.NET Core. W tej sekcji przedstawiono sposób tłumaczenia najczęściej używanych System.Web.HttpContext właściwości do nowego Microsoft.AspNetCore.Http.HttpContext
elementu .
HttpContext
Element HttpContext.Items tłumaczy się na:
IDictionary<object, object> items = httpContext.Items;
Unikatowy identyfikator żądania (bez odpowiednika System.Web.HttpContext)
Nadaje unikatowy identyfikator dla każdego żądania. Bardzo przydatne do uwzględnienia w dziennikach.
string requestId = httpContext.TraceIdentifier;
HttpContext.Request
HttpContext.Request.HttpMethod przekłada się na:
string httpMethod = httpContext.Request.Method;
HttpContext.Request.QueryString przekłada się 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 i HttpContext.Request.RawUrl tłumaczą na:
// using Microsoft.AspNetCore.Http.Extensions;
var url = httpContext.Request.GetDisplayUrl();
HttpContext.Request.IsSecureConnection tłumaczy się na:
var isSecureConnection = httpContext.Request.IsHttps;
HttpContext.Request.UserHostAddress przekłada się na:
var userHostAddress = httpContext.Connection.RemoteIpAddress?.ToString();
HttpContext.Request.Cookies tłumaczy się 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 tłumaczy się na:
var routeValue = httpContext.GetRouteValue("key");
HttpContext.Request.Headers przekłada się 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();
Element HttpContext.Request.UserAgent przekłada się na:
string userAgent = headersDictionary[HeaderNames.UserAgent].ToString();
HttpContext.Request.UrlReferrer tłumaczy się na:
string urlReferrer = headersDictionary[HeaderNames.Referer].ToString();
HttpContext.Request.ContentType tłumaczy się 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 tłumaczy się 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"];
}
Ostrzeżenie
Odczytaj wartości formularza tylko wtedy, gdy podtyp zawartości to x-www-form-urlencoded lub form-data.
HttpContext.Request.InputStream tłumaczy się na:
string inputBody;
using (var reader = new System.IO.StreamReader(
httpContext.Request.Body, System.Text.Encoding.UTF8))
{
inputBody = reader.ReadToEnd();
}
Ostrzeżenie
Użyj tego kodu tylko w programie obsługi oprogramowania pośredniczącego typu na końcu potoku.
Nieprzetworzona treść można odczytać, jak pokazano powyżej tylko raz na żądanie. Oprogramowanie pośredniczące próbujące odczytać treść po pierwszym przeczytaniu odczytuje pustą treść.
Nie dotyczy to odczytywania formularza, jak pokazano wcześniej, ponieważ odbywa się to z buforu.
HttpContext.Response
Tłumaczenie httpContext.Response.Status i HttpContext.Response.StatusDescription na:
// using Microsoft.AspNetCore.Http;
httpContext.Response.StatusCode = StatusCodes.Status200OK;
HttpContext.Response.ContentEncoding i HttpContext.Response.ContentType tłumaczą 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 samodzielnie tłumaczy się również na:
httpContext.Response.ContentType = "text/html";
HttpContext.Response.Output przekłada się na:
string responseContent = GetResponseContent();
await httpContext.Response.WriteAsync(responseContent);
HttpContext.Response.TransmitFile
Obsługa pliku jest omawiana w temacie Funkcje żądań w ASP.NET Core.
HttpContext.Response.Headers
Wysyłanie nagłówków odpowiedzi jest skomplikowane przez fakt, że jeśli ustawisz je po zapisaniu czegokolwiek do treści odpowiedzi, nie zostaną wysłane.
Rozwiązaniem jest ustawienie metody wywołania zwrotnego, która zostanie wywołana bezpośrednio przed rozpoczęciem pisania odpowiedzi. Najlepiej jest to zrobić na początku Invoke
metody w oprogramowania pośredniczącego. Jest to ta metoda wywołania zwrotnego, która ustawia nagłówki odpowiedzi.
Poniższy kod ustawia metodę wywołania zwrotnego o nazwie SetHeaders
:
public async Task Invoke(HttpContext httpContext)
{
// ...
httpContext.Response.OnStarting(SetHeaders, state: httpContext);
Metoda SetHeaders
wywołania zwrotnego wygląda następująco:
// 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
Pliki cookie są przesyłane do przeglądarki w nagłówku set-responseCookie . W związku z tym wysyłanie plików cookie wymaga tego samego wywołania zwrotnego, co do wysyłania nagłówków odpowiedzi:
public async Task Invoke(HttpContext httpContext)
{
// ...
httpContext.Response.OnStarting(SetCookies, state: httpContext);
httpContext.Response.OnStarting(SetHeaders, state: httpContext);
Metoda SetCookies
wywołania zwrotnego wygląda następująco:
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);
}