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:

Procedura obsługi modułów

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:

  1. 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.

  2. 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:

Oprogramowanie pośredniczące i moduły są przetwarzane w innej kolejności:

Zwarcie oprogramowania pośredniczącego autoryzacji żądanie dla użytkownika, który nie jest autoryzowany. Żądanie strony Indeks jest dozwolone i przetwarzane przez oprogramowanie pośredniczące MVC. Żądanie raportu sprzedaży jest dozwolone i przetwarzane przez niestandardowe oprogramowanie pośredniczące raportu.

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, EndRequestitp.) 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:

  1. Lambda, która pobiera HttpContext element i zwraca true , 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.

  2. 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:

  1. 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; }
    }
    
  2. 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.

  3. 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 obiektem MyMiddlewareOptions , który ma rzeczywiste opcje.

    Zaktualizuj klasę Startup :

    1. Jeśli używasz polecenia appsettings.json, dodaj go do konstruktora konfiguracji w konstruktorze Startup :

      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();
      }
      
    2. 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();
      }
      
    3. 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();
      }
      
  4. 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.

  1. 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"
      }
    }
    
  2. 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?}");
        });
    }
    
  3. 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 metody UseMiddleware). Gdy UseMiddleware 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 zaimplementowanie IOptionsmetody , 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.HttpContextelementu .

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.IsSecure Połączenie ion przekłada się na:

var isSecureConnection = httpContext.Request.IsHttps;

HttpContext.Request.UserHostAddress przekłada się na:

var userHostAddress = httpContext.Connection.RemoteIpAddress?.ToString();

HttpContext.Request.Cookies przekłada 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

Cookies przejdź do przeglądarki w nagłówku Set-responseCookie . W związku z tym wysyłanie cookies 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); 
}

Dodatkowe zasoby