Memigrasikan pengatur dan modul HTTP ke middleware ASP.NET Core
Artikel ini memperlihatkan cara memigrasikan modul dan handler HTTP ASP.NET yang ada dari system.webserver ke middleware ASP.NET Core.
Modul dan handler ditinjau kembali
Sebelum melanjutkan ke ASP.NET middleware Core, mari kita rekap terlebih dahulu cara kerja modul dan handler HTTP:
Handler adalah:
Kelas yang mengimplementasikan IHttpHandler
Digunakan untuk menangani permintaan dengan nama file atau ekstensi tertentu, seperti .report
Modulnya adalah:
Kelas yang mengimplementasikan IHttpModule
Dipanggil untuk setiap permintaan
Dapat melakukan sirkuit pendek (hentikan pemrosesan permintaan lebih lanjut)
Dapat menambahkan ke respons HTTP, atau membuat respons http mereka sendiri
Urutan proses modul permintaan masuk ditentukan oleh:
Serangkaian peristiwa yang dipicu oleh ASP.NET, seperti BeginRequest dan AuthenticateRequest. Untuk daftar lengkapnya, lihat System.Web.HttpApplication. Setiap modul dapat membuat handler untuk satu atau beberapa peristiwa.
Untuk peristiwa yang sama, urutan konfigurasinya di Web.config.
Selain modul, Anda dapat menambahkan handler untuk peristiwa siklus hidup ke file Anda Global.asax.cs
. Handler ini berjalan setelah handler dalam modul yang dikonfigurasi.
Dari handler dan modul hingga middleware
Middleware lebih sederhana daripada modul dan handler HTTP:
Modul, handler,
Global.asax.cs
, Web.config (kecuali untuk konfigurasi IIS) dan siklus hidup aplikasi hilangPeran modul dan handler telah diambil alih oleh middleware
Middleware dikonfigurasi menggunakan kode daripada di Web.config
- Pencabangan alur memungkinkan Anda mengirim permintaan ke middleware tertentu, berdasarkan tidak hanya URL tetapi juga pada header permintaan, string kueri, dll.
- Pencabangan alur memungkinkan Anda mengirim permintaan ke middleware tertentu, berdasarkan tidak hanya URL tetapi juga pada header permintaan, string kueri, dll.
Middleware sangat mirip dengan modul:
Dipanggil secara prinsip untuk setiap permintaan
Dapat membuat sirkuit pendek permintaan, dengan tidak meneruskan permintaan ke middleware berikutnya
Mampu membuat respons HTTP mereka sendiri
Middleware dan modul diproses dalam urutan yang berbeda:
Urutan middleware didasarkan pada urutan di mana mereka dimasukkan ke dalam alur permintaan, sementara urutan modul terutama didasarkan pada System.Web.HttpApplication peristiwa.
Urutan middleware untuk respons adalah kebalikan dari itu untuk permintaan, sementara urutan modul sama untuk permintaan dan respons
Perhatikan bagaimana pada gambar di atas, middleware autentikasi sirkuit pendek permintaan.
Memigrasikan kode modul ke middleware
Modul HTTP yang ada akan terlihat mirip dengan ini:
// 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.
}
}
}
Seperti yang ditunjukkan di halaman Middleware , middleware ASP.NET Core adalah kelas yang mengekspos Invoke
metode mengambil HttpContext
dan mengembalikan Task
. Middleware baru Anda akan terlihat seperti ini:
// 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>();
}
}
}
Templat middleware sebelumnya diambil dari bagian tentang menulis middleware.
Kelas pembantu MyMiddlewareExtensions memudahkan konfigurasi middleware Anda di kelas Anda Startup
. Metode menambahkan UseMyMiddleware
kelas middleware Anda ke alur permintaan. Layanan yang diperlukan oleh middleware disuntikkan ke konstruktor middleware.
Modul Anda mungkin mengakhiri permintaan, misalnya jika pengguna tidak diotorisasi:
// 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 menangani ini dengan tidak memanggil Invoke
middleware berikutnya di alur. Perlu diingat bahwa ini tidak sepenuhnya mengakhiri permintaan, karena middleware sebelumnya masih akan dipanggil ketika respons kembali melalui alur.
// 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.
}
Saat memigrasikan fungsionalitas modul ke middleware baru, Anda mungkin menemukan bahwa kode Anda tidak dikompilasi karena HttpContext
kelas telah berubah secara signifikan di ASP.NET Core. Nantinya, Anda akan melihat cara bermigrasi ke ASP.NET Core HttpContext baru.
Memigrasikan penyisipan modul ke dalam alur permintaan
Modul HTTP biasanya ditambahkan ke alur permintaan menggunakan 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>
Konversikan ini dengan menambahkan middleware baru Anda ke alur permintaan di kelas Anda 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?}");
});
}
Tempat yang tepat dalam alur tempat Anda memasukkan middleware baru tergantung pada peristiwa yang ditanganinya sebagai modul (BeginRequest
, , EndRequest
dll.) dan urutannya dalam daftar modul Anda di Web.config.
Seperti yang dinyatakan sebelumnya, tidak ada siklus hidup aplikasi di ASP.NET Core dan urutan di mana respons diproses oleh middleware berbeda dari urutan yang digunakan oleh modul. Ini bisa membuat keputusan pemesanan Anda lebih menantang.
Jika pemesanan menjadi masalah, Anda dapat membagi modul Anda menjadi beberapa komponen middleware yang dapat dipesan secara independen.
Memigrasikan kode handler ke middleware
Handler HTTP terlihat seperti ini:
// 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";
}
}
}
Dalam proyek ASP.NET Core Anda, Anda akan menerjemahkan ini ke middleware yang mirip dengan ini:
// 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>();
}
}
}
Middleware ini sangat mirip dengan middleware yang sesuai dengan modul. Satu-satunya perbedaan nyata adalah bahwa di sini tidak ada panggilan ke _next.Invoke(context)
. Itu masuk akal, karena handler berada di akhir alur permintaan, sehingga tidak akan ada middleware berikutnya untuk dipanggil.
Memigrasikan penyisipan handler ke dalam alur permintaan
Mengonfigurasi handler HTTP dilakukan di Web.config dan terlihat seperti ini:
<?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>
Anda dapat mengonversi ini dengan menambahkan middleware handler baru Anda ke alur permintaan di kelas Anda Startup
, mirip dengan middleware yang dikonversi dari modul. Masalah dengan pendekatan itu adalah bahwa itu akan mengirim semua permintaan ke middleware handler baru Anda. Namun, Anda hanya ingin permintaan dengan ekstensi tertentu mencapai middleware Anda. Itu akan memberi Anda fungsionalitas yang sama dengan handler HTTP Anda.
Salah satu solusinya adalah mencabangkan alur untuk permintaan dengan ekstensi tertentu, menggunakan MapWhen
metode ekstensi. Anda melakukan ini dalam metode yang sama Configure
di mana Anda menambahkan middleware lainnya:
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
mengambil parameter ini:
Lambda yang mengambil
HttpContext
dan mengembalikantrue
jika permintaan harus turun ke cabang. Ini berarti Anda dapat mencabangkan permintaan tidak hanya berdasarkan ekstensinya, tetapi juga pada header permintaan, parameter string kueri, dll.Lambda yang mengambil
IApplicationBuilder
dan menambahkan semua middleware untuk cabang. Ini berarti Anda dapat menambahkan middleware tambahan ke cabang di depan middleware handler Anda.
Middleware ditambahkan ke alur sebelum cabang akan dipanggil pada semua permintaan; cabang tidak akan berdampak pada mereka.
Memuat opsi middleware menggunakan pola opsi
Beberapa modul dan handler memiliki opsi konfigurasi yang disimpan di Web.config. Namun, di ASP.NET Core, model konfigurasi baru digunakan sebagai pengganti Web.config.
Sistem konfigurasi baru memberi Anda opsi ini untuk menyelesaikan ini:
Langsung masukkan opsi ke middleware, seperti yang ditunjukkan di bagian berikutnya.
Gunakan pola opsi:
Buat kelas untuk menyimpan opsi middleware Anda, misalnya:
public class MyMiddlewareOptions { public string Param1 { get; set; } public string Param2 { get; set; } }
Menyimpan nilai opsi
Sistem konfigurasi memungkinkan Anda menyimpan nilai opsi di mana pun Anda inginkan. Namun, sebagian besar situs menggunakan
appsettings.json
, jadi kita akan mengambil pendekatan itu:{ "MyMiddlewareOptionsSection": { "Param1": "Param1Value", "Param2": "Param2Value" } }
MyMiddlewareOptionsSection di sini adalah nama bagian. Tidak harus sama dengan nama kelas opsi Anda.
Mengaitkan nilai opsi dengan kelas opsi
Pola opsi menggunakan ASP.NET kerangka kerja injeksi dependensi Core untuk mengaitkan jenis opsi (seperti
MyMiddlewareOptions
) denganMyMiddlewareOptions
objek yang memiliki opsi aktual.Perbarui kelas Anda
Startup
:Jika Anda menggunakan
appsettings.json
, tambahkan ke penyusun konfigurasi diStartup
konstruktor: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(); }
Konfigurasikan layanan opsi:
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(); }
Kaitkan opsi Anda dengan kelas opsi Anda:
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(); }
Masukkan opsi ke konstruktor middleware Anda. Ini mirip dengan menyuntikkan opsi ke pengontrol.
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 } }
Metode ekstensi UseMiddleware yang menambahkan middleware Anda ke
IApplicationBuilder
mengurus injeksi dependensi.Ini tidak terbatas pada
IOptions
objek. Objek lain yang diperlukan middleware Anda dapat disuntikkan dengan cara ini.
Memuat opsi middleware melalui injeksi langsung
Pola opsi memiliki keuntungan karena menciptakan kopling longgar antara nilai opsi dan konsumennya. Setelah Anda mengaitkan kelas opsi dengan nilai opsi aktual, kelas lain apa pun bisa mendapatkan akses ke opsi melalui kerangka kerja injeksi dependensi. Tidak perlu meneruskan nilai opsi.
Ini memecah meskipun jika Anda ingin menggunakan middleware yang sama dua kali, dengan opsi yang berbeda. Misalnya middleware otorisasi yang digunakan di cabang yang berbeda yang memungkinkan peran yang berbeda. Anda tidak dapat mengaitkan dua objek opsi yang berbeda dengan satu kelas opsi.
Solusinya adalah mendapatkan objek opsi dengan nilai opsi aktual di kelas Anda Startup
dan meneruskan objek tersebut langsung ke setiap instans middleware Anda.
Menambahkan kunci kedua ke
appsettings.json
Untuk menambahkan sekumpulan opsi kedua ke
appsettings.json
file, gunakan kunci baru untuk mengidentifikasinya secara unik:{ "MyMiddlewareOptionsSection2": { "Param1": "Param1Value2", "Param2": "Param2Value2" }, "MyMiddlewareOptionsSection": { "Param1": "Param1Value", "Param2": "Param2Value" } }
Ambil nilai opsi dan teruskan ke middleware. Metode
Use...
ekstensi (yang menambahkan middleware Anda ke alur) adalah tempat logis untuk meneruskan nilai opsi: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?}"); }); }
Aktifkan middleware untuk mengambil parameter opsi. Berikan kelebihan beban
Use...
metode ekstensi (yang mengambil parameter opsi dan meneruskannya keUseMiddleware
). KetikaUseMiddleware
dipanggil dengan parameter, ia meneruskan parameter ke konstruktor middleware Anda saat membuat instans objek 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)); } }
Perhatikan bagaimana ini membungkus objek opsi dalam
OptionsWrapper
objek. Ini mengimplementasikanIOptions
, seperti yang diharapkan oleh konstruktor middleware.
Bermigrasi ke HttpContext baru
Anda melihat sebelumnya bahwa Invoke
metode di middleware Anda mengambil parameter jenis HttpContext
:
public async Task Invoke(HttpContext context)
HttpContext
secara signifikan berubah dalam ASP.NET Core. Bagian ini menunjukkan cara menerjemahkan properti yang paling umum digunakan ke System.Web.HttpContext yang baru Microsoft.AspNetCore.Http.HttpContext
.
HttpContext
HttpContext.Items diterjemahkan ke:
IDictionary<object, object> items = httpContext.Items;
ID permintaan unik (tidak ada mitra System.Web.HttpContext)
Memberi Anda id unik untuk setiap permintaan. Sangat berguna untuk disertakan dalam log Anda.
string requestId = httpContext.TraceIdentifier;
HttpContext.Request
HttpContext.Request.HttpMethod diterjemahkan ke:
string httpMethod = httpContext.Request.Method;
HttpContext.Request.QueryString diterjemahkan ke:
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 dan HttpContext.Request.RawUrl menerjemahkan ke:
// using Microsoft.AspNetCore.Http.Extensions;
var url = httpContext.Request.GetDisplayUrl();
HttpContext.Request.IsSecureConnection diterjemahkan ke:
var isSecureConnection = httpContext.Request.IsHttps;
HttpContext.Request.UserHostAddress diterjemahkan ke:
var userHostAddress = httpContext.Connection.RemoteIpAddress?.ToString();
HttpContext.Request.Cookies diterjemahkan ke:
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 diterjemahkan ke:
var routeValue = httpContext.GetRouteValue("key");
HttpContext.Request.Headers diterjemahkan ke:
// 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 diterjemahkan ke:
string userAgent = headersDictionary[HeaderNames.UserAgent].ToString();
HttpContext.Request.UrlReferrer diterjemahkan ke:
string urlReferrer = headersDictionary[HeaderNames.Referer].ToString();
HttpContext.Request.ContentType diterjemahkan ke:
// 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 diterjemahkan ke:
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"];
}
Peringatan
Baca nilai formulir hanya jika sub jenis konten adalah x-www-form-urlencoded atau form-data.
HttpContext.Request.InputStream diterjemahkan ke:
string inputBody;
using (var reader = new System.IO.StreamReader(
httpContext.Request.Body, System.Text.Encoding.UTF8))
{
inputBody = reader.ReadToEnd();
}
Peringatan
Gunakan kode ini hanya dalam middleware jenis handler, di akhir alur.
Anda dapat membaca tubuh mentah seperti yang ditunjukkan di atas hanya sekali per permintaan. Middleware yang mencoba membaca isi setelah bacaan pertama akan membaca isi kosong.
Ini tidak berlaku untuk membaca formulir seperti yang ditunjukkan sebelumnya, karena itu dilakukan dari buffer.
HttpContext.Response
HttpContext.Response.Status dan HttpContext.Response.StatusDescription diterjemahkan ke:
// using Microsoft.AspNetCore.Http;
httpContext.Response.StatusCode = StatusCodes.Status200OK;
HttpContext.Response.ContentEncoding dan HttpContext.Response.ContentType diterjemahkan ke:
// 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 sendiri juga diterjemahkan ke:
httpContext.Response.ContentType = "text/html";
HttpContext.Response.Output diterjemahkan ke:
string responseContent = GetResponseContent();
await httpContext.Response.WriteAsync(responseContent);
HttpContext.Response.TransmitFile
Menyajikan file dibahas dalam Fitur Permintaan di ASP.NET Core.
HttpContext.Response.Headers
Mengirim header respons rumit oleh fakta bahwa jika Anda mengaturnya setelah apa pun ditulis ke isi respons, header tersebut tidak akan dikirim.
Solusinya adalah mengatur metode panggilan balik yang akan dipanggil tepat sebelum menulis ke respons dimulai. Ini paling baik dilakukan pada awal Invoke
metode di middleware Anda. Metode panggilan balik inilah yang mengatur header respons Anda.
Kode berikut menetapkan metode panggilan balik yang disebut SetHeaders
:
public async Task Invoke(HttpContext httpContext)
{
// ...
httpContext.Response.OnStarting(SetHeaders, state: httpContext);
Metode SetHeaders
panggilan balik akan terlihat seperti ini:
// 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
Cookie melakukan perjalanan ke browser di header Set-Cookie respons. Akibatnya, mengirim cookie memerlukan panggilan balik yang sama seperti yang digunakan untuk mengirim header respons:
public async Task Invoke(HttpContext httpContext)
{
// ...
httpContext.Response.OnStarting(SetCookies, state: httpContext);
httpContext.Response.OnStarting(SetHeaders, state: httpContext);
Metode SetCookies
panggilan balik akan terlihat seperti berikut:
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);
}
Sumber Daya Tambahan:
ASP.NET Core