ASP.NET Core için gRPC'de kimlik doğrulaması ve yetkilendirme
Uyarı
ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.
Yayınlayan James Newton-King
Örnek kodu görüntüleme veya indirme (indirme)
gRPC hizmetini çağıran kullanıcıların kimliğini doğrulama
gRPC, bir kullanıcıyı her çağrıyla ilişkilendirmek için ASP.NET Core kimlik doğrulaması ile kullanılabilir.
Aşağıda gRPC ve ASP.NET Core kimlik doğrulaması kullanan bir örnek Program.cs
verilmiştir:
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapGrpcService<GreeterService>();
Not
ASP.NET Core kimlik doğrulama ara yazılımını kaydetme sırası önemlidir. Her zaman ve UseAuthorization
sonrasında UseRouting
ve öncesinde UseEndpoints
öğesini arayınUseAuthentication
.
Uygulamanızın çağrı sırasında kullandığı kimlik doğrulama mekanizmasının yapılandırılması gerekir. kimlik doğrulama yapılandırması eklenir Program.cs
ve uygulamanızın kullandığı kimlik doğrulama mekanizmasına bağlı olarak farklı olacaktır.
Kimlik doğrulaması ayarlandıktan sonra, kullanıcı aracılığıyla bir gRPC hizmet yöntemlerinde ServerCallContext
erişilebilir.
public override Task<BuyTicketsResponse> BuyTickets(
BuyTicketsRequest request, ServerCallContext context)
{
var user = context.GetHttpContext().User;
// ... access data from ClaimsPrincipal ...
}
Taşıyıcı belirteç kimlik doğrulaması
İstemci, kimlik doğrulaması için bir erişim belirteci sağlayabilir. Sunucu belirteci doğrular ve kullanıcıyı tanımlamak için kullanır.
Sunucuda taşıyıcı belirteç kimlik doğrulaması JWT Taşıyıcı ara yazılımı kullanılarak yapılandırılır.
.NET gRPC istemcisinde belirteç, koleksiyonu kullanılarak Metadata
çağrılarla gönderilebilir. Koleksiyondaki Metadata
girdiler http üst bilgileri olarak gRPC çağrısıyla gönderilir:
public bool DoAuthenticatedCall(
Ticketer.TicketerClient client, string token)
{
var headers = new Metadata();
headers.Add("Authorization", $"Bearer {token}");
var request = new BuyTicketsRequest { Count = 1 };
var response = await client.BuyTicketsAsync(request, headers);
return response.Success;
}
Taşıyıcı belirtecini ile ayarlama CallCredentials
Bir kanalda yapılandırma ChannelCredentials
, belirteci gRPC çağrılarıyla hizmete göndermenin alternatif bir yoludur. , ChannelCredentials
öğesini otomatik olarak ayarlamak Metadata
için bir yol sağlayan öğesini içerebilirCallCredentials
.
kullanmanın CallCredentials
avantajları:
- Kimlik doğrulaması kanalda merkezi olarak yapılandırılır. Belirtecin gRPC çağrısına el ile sağlanması gerekmez.
- Geri
CallCredentials.FromInterceptor
çağırma zaman uyumsuzdur. Çağrı kimlik bilgileri gerekirse bir dış sistemden kimlik bilgisi belirteci getirebilir. Geri çağırma içindeki zaman uyumsuz yöntemler üzerindeAuthInterceptorContext
kullanmalıdırCancellationToken
.
Not
CallCredentials
yalnızca kanalın GÜVENLIĞI TLS ile sağlandığında uygulanır. Güvenli olmayan bir bağlantı üzerinden kimlik doğrulama üst bilgileri göndermenin güvenlik açısından etkileri vardır ve üretim ortamlarında yapılmamalıdır. Bir uygulama, kanalı bu davranışı yoksayacak şekilde yapılandırabilir ve her zaman kanalda ayar UnsafeUseInsecureChannelCallCredentials
yaparak kullanabilirCallCredentials
.
Aşağıdaki örnekteki kimlik bilgisi, kanalı her gRPC çağrısıyla belirteci gönderecek şekilde yapılandırıyor:
private static GrpcChannel CreateAuthenticatedChannel(ITokenProvder tokenProvider)
{
var credentials = CallCredentials.FromInterceptor(async (context, metadata) =>
{
var token = await tokenProvider.GetTokenAsync(context.CancellationToken);
metadata.Add("Authorization", $"Bearer {token}");
});
var channel = GrpcChannel.ForAddress(address, new GrpcChannelOptions
{
Credentials = ChannelCredentials.Create(new SslCredentials(), credentials)
});
return channel;
}
gRPC istemci fabrikası ile taşıyıcı belirteci
gRPC istemci fabrikası kullanarak AddCallCredentials
taşıyıcı belirteç gönderen istemciler oluşturabilir. Bu yöntem Grpc.Net.ClientFactory 2.46.0 veya sonraki bir sürümde kullanılabilir.
geçirilen AddCallCredentials
temsilci her gRPC çağrısı için yürütülür:
builder.Services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddCallCredentials((context, metadata) =>
{
if (!string.IsNullOrEmpty(_token))
{
metadata.Add("Authorization", $"Bearer {_token}");
}
return Task.CompletedTask;
});
Bağımlılık ekleme (DI) ile AddCallCredentials
birleştirilebilir. Aşırı yükleme, kapsamlı ve geçici hizmetler kullanılarak DI'den bir hizmet oluşturmak için kullanılabilen temsilciye geçerIServiceProvider
.
Aşağıdakilere sahip bir uygulamayı düşünün:
- Taşıyıcı belirteci almak için kullanıcı tanımlı
ITokenProvider
.ITokenProvider
, kapsamlı bir yaşam süresiyle DI'ye kaydedilir. - gRPC istemci fabrikası, gRPC hizmetlerine ve Web API denetleyicilerine eklenen istemcileri oluşturmak için yapılandırılır.
- gRPC çağrıları taşıyıcı belirteci almak için kullanmalıdır
ITokenProvider
.
public interface ITokenProvider
{
Task<string> GetTokenAsync(CancellationToken cancellationToken);
}
public class AppTokenProvider : ITokenProvider
{
private string _token;
public async Task<string> GetTokenAsync(CancellationToken cancellationToken)
{
if (_token == null)
{
// App code to resolve the token here.
}
return _token;
}
}
builder.Services.AddScoped<ITokenProvider, AppTokenProvider>();
builder.Services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddCallCredentials(async (context, metadata, serviceProvider) =>
{
var provider = serviceProvider.GetRequiredService<ITokenProvider>();
var token = await provider.GetTokenAsync(context.CancellationToken);
metadata.Add("Authorization", $"Bearer {token}");
}));
Yukarıdaki kod:
- ve
AppTokenProvider
öğesini tanımlarITokenProvider
. Bu türler gRPC çağrıları için kimlik doğrulama belirtecini çözümlemeyi işler. AppTokenProvider
Türü kapsamlı bir yaşam süresi içinde DI'ye kaydeder.AppTokenProvider
belirteci önbelleğe alır, böylece yalnızca kapsamdaki ilk çağrının hesaplanması gerekir.- Türü istemci fabrikasına
GreeterClient
kaydeder. - Bu istemci için yapılandırılır
AddCallCredentials
. Temsilci her çağrı yapıldığında yürütülür ve tarafındanITokenProvider
döndürülen belirteci meta veriye ekler.
İstemci sertifikası kimlik doğrulaması
İstemci alternatif olarak kimlik doğrulaması için bir istemci sertifikası sağlayabilir. Sertifika kimlik doğrulaması , ASP.NET Core'a varmadan çok daha önce TLS düzeyinde gerçekleşir. İstek ASP.NET Core'a girdiğinde, istemci sertifikası kimlik doğrulama paketi sertifikayı bir ClaimsPrincipal
olarak çözümlemenize olanak tanır.
Not
Sunucuyu istemci sertifikalarını kabul etmek için yapılandırın. , IIS ve Azure'da Kestrelistemci sertifikalarını kabul etme hakkında bilgi için bkz . ASP.NET Core'da sertifika kimlik doğrulamasını yapılandırma.
.NET gRPC istemcisinde, daha sonra gRPC istemcisini oluşturmak için kullanılan istemci sertifikası eklenir HttpClientHandler
:
public Ticketer.TicketerClient CreateClientWithCert(
string baseAddress,
X509Certificate2 certificate)
{
// Add client cert to the handler
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate);
// Create the gRPC channel
var channel = GrpcChannel.ForAddress(baseAddress, new GrpcChannelOptions
{
HttpHandler = handler
});
return new Ticketer.TicketerClient(channel);
}
Diğer kimlik doğrulama mekanizmaları
Birçok ASP.NET Core destekli kimlik doğrulama mekanizması gRPC ile çalışır:
- Microsoft Entra Kimlik
- İstemci Sertifikası
- IdentityServer
- JWT Belirteci
- OAuth 2.0
- OpenID Connect
- WS-Federation
Sunucuda kimlik doğrulamasını yapılandırma hakkında daha fazla bilgi için bkz . ASP.NET Çekirdek kimlik doğrulaması.
gRPC istemcisini kimlik doğrulaması kullanacak şekilde yapılandırmak, kullandığınız kimlik doğrulama mekanizmasına bağlıdır. Önceki taşıyıcı belirteci ve istemci sertifikası örnekleri, gRPC istemcisinin gRPC çağrılarıyla kimlik doğrulama meta verilerini gönderecek şekilde yapılandırılmasının birkaç yolunu gösterir:
- Kesin olarak yazılan gRPC istemcileri dahili olarak kullanır
HttpClient
. Kimlik doğrulaması üzerinde HttpClientHandlerveya öğesine özel HttpMessageHandler örneklerHttpClient
eklenerek yapılandırılabilir. - Her gRPC çağrısının isteğe bağlı
CallOptions
bir bağımsız değişkeni vardır. Özel üst bilgiler seçeneğin üst bilgi koleksiyonu kullanılarak gönderilebilir.
Not
Windows Kimlik Doğrulaması (NTLM/Kerberos/Negotiate) gRPC ile kullanılamaz. gRPC HTTP/2 gerektirir ve HTTP/2, Windows Kimlik Doğrulamayı desteklemez.
Kullanıcılara hizmetlere ve hizmet yöntemlerine erişme yetkisi verme
Varsayılan olarak, bir hizmetteki tüm yöntemler kimliği doğrulanmamış kullanıcılar tarafından çağrılabilir. Kimlik doğrulaması gerektirmek için özniteliğini [Authorize]
hizmete uygulayın:
[Authorize]
public class TicketerService : Ticketer.TicketerBase
{
}
Yalnızca belirli yetkilendirme ilkeleriyle eşleşen kullanıcılara erişimi kısıtlamak için özniteliğin [Authorize]
oluşturucu bağımsız değişkenlerini ve özelliklerini kullanabilirsiniz. Örneğin, adlı MyAuthorizationPolicy
özel bir yetkilendirme ilkeniz varsa, yalnızca bu ilkeyle eşleşen kullanıcıların aşağıdaki kodu kullanarak hizmete erişebildiğinden emin olun:
[Authorize("MyAuthorizationPolicy")]
public class TicketerService : Ticketer.TicketerBase
{
}
Tek tek hizmet yöntemlerinde [Authorize]
de özniteliği uygulanabilir. Geçerli kullanıcı hem yönteme hem de sınıfa uygulanan ilkeler ile eşleşmiyorsa, çağırana bir hata döndürülür:
[Authorize]
public class TicketerService : Ticketer.TicketerBase
{
public override Task<AvailableTicketsResponse> GetAvailableTickets(
Empty request, ServerCallContext context)
{
// ... buy tickets for the current user ...
}
[Authorize("Administrators")]
public override Task<BuyTicketsResponse> RefundTickets(
BuyTicketsRequest request, ServerCallContext context)
{
// ... refund tickets (something only Administrators can do) ..
}
}
Ek kaynaklar
Örnek kodu görüntüleme veya indirme (indirme)
gRPC hizmetini çağıran kullanıcıların kimliğini doğrulama
gRPC, bir kullanıcıyı her çağrıyla ilişkilendirmek için ASP.NET Core kimlik doğrulaması ile kullanılabilir.
Aşağıda gRPC ve ASP.NET Core kimlik doğrulaması kullanan bir örnek Startup.Configure
verilmiştir:
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
});
}
Not
ASP.NET Core kimlik doğrulama ara yazılımını kaydetme sırası önemlidir. Her zaman ve UseAuthorization
sonrasında UseRouting
ve öncesinde UseEndpoints
öğesini arayınUseAuthentication
.
Uygulamanızın çağrı sırasında kullandığı kimlik doğrulama mekanizmasının yapılandırılması gerekir. kimlik doğrulama yapılandırması eklenir Startup.ConfigureServices
ve uygulamanızın kullandığı kimlik doğrulama mekanizmasına bağlı olarak farklı olacaktır.
Kimlik doğrulaması ayarlandıktan sonra, kullanıcı aracılığıyla bir gRPC hizmet yöntemlerinde ServerCallContext
erişilebilir.
public override Task<BuyTicketsResponse> BuyTickets(
BuyTicketsRequest request, ServerCallContext context)
{
var user = context.GetHttpContext().User;
// ... access data from ClaimsPrincipal ...
}
Taşıyıcı belirteç kimlik doğrulaması
İstemci, kimlik doğrulaması için bir erişim belirteci sağlayabilir. Sunucu belirteci doğrular ve kullanıcıyı tanımlamak için kullanır.
Sunucuda taşıyıcı belirteç kimlik doğrulaması JWT Taşıyıcı ara yazılımı kullanılarak yapılandırılır.
.NET gRPC istemcisinde belirteç, koleksiyonu kullanılarak Metadata
çağrılarla gönderilebilir. Koleksiyondaki Metadata
girdiler http üst bilgileri olarak gRPC çağrısıyla gönderilir:
public bool DoAuthenticatedCall(
Ticketer.TicketerClient client, string token)
{
var headers = new Metadata();
headers.Add("Authorization", $"Bearer {token}");
var request = new BuyTicketsRequest { Count = 1 };
var response = await client.BuyTicketsAsync(request, headers);
return response.Success;
}
Taşıyıcı belirtecini ile ayarlama CallCredentials
Bir kanalda yapılandırma ChannelCredentials
, belirteci gRPC çağrılarıyla hizmete göndermenin alternatif bir yoludur. , ChannelCredentials
öğesini otomatik olarak ayarlamak Metadata
için bir yol sağlayan öğesini içerebilirCallCredentials
.
kullanmanın CallCredentials
avantajları:
- Kimlik doğrulaması kanalda merkezi olarak yapılandırılır. Belirtecin gRPC çağrısına el ile sağlanması gerekmez.
- Geri
CallCredentials.FromInterceptor
çağırma zaman uyumsuzdur. Çağrı kimlik bilgileri gerekirse bir dış sistemden kimlik bilgisi belirteci getirebilir. Geri çağırma içindeki zaman uyumsuz yöntemler üzerindeAuthInterceptorContext
kullanmalıdırCancellationToken
.
Not
CallCredentials
yalnızca kanalın GÜVENLIĞI TLS ile sağlandığında uygulanır. Güvenli olmayan bir bağlantı üzerinden kimlik doğrulama üst bilgileri göndermenin güvenlik açısından etkileri vardır ve üretim ortamlarında yapılmamalıdır. Bir uygulama, kanalı bu davranışı yoksayacak şekilde yapılandırabilir ve her zaman kanalda ayar UnsafeUseInsecureChannelCallCredentials
yaparak kullanabilirCallCredentials
.
Aşağıdaki örnekteki kimlik bilgisi, kanalı her gRPC çağrısıyla belirteci gönderecek şekilde yapılandırıyor:
private static GrpcChannel CreateAuthenticatedChannel(ITokenProvder tokenProvider)
{
var credentials = CallCredentials.FromInterceptor(async (context, metadata) =>
{
var token = await tokenProvider.GetTokenAsync(context.CancellationToken);
metadata.Add("Authorization", $"Bearer {token}");
});
var channel = GrpcChannel.ForAddress(address, new GrpcChannelOptions
{
Credentials = ChannelCredentials.Create(new SslCredentials(), credentials)
});
return channel;
}
gRPC istemci fabrikası ile taşıyıcı belirteci
gRPC istemci fabrikası kullanarak AddCallCredentials
taşıyıcı belirteç gönderen istemciler oluşturabilir. Bu yöntem Grpc.Net.ClientFactory 2.46.0 veya sonraki bir sürümde kullanılabilir.
geçirilen AddCallCredentials
temsilci her gRPC çağrısı için yürütülür:
services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddCallCredentials((context, metadata) =>
{
if (!string.IsNullOrEmpty(_token))
{
metadata.Add("Authorization", $"Bearer {_token}");
}
return Task.CompletedTask;
});
Bağımlılık ekleme (DI) ile AddCallCredentials
birleştirilebilir. Aşırı yükleme, kapsamlı ve geçici hizmetler kullanılarak DI'den bir hizmet oluşturmak için kullanılabilen temsilciye geçerIServiceProvider
.
Aşağıdakilere sahip bir uygulamayı düşünün:
- Taşıyıcı belirteci almak için kullanıcı tanımlı
ITokenProvider
.ITokenProvider
, kapsamlı bir yaşam süresiyle DI'ye kaydedilir. - gRPC istemci fabrikası, gRPC hizmetlerine ve Web API denetleyicilerine eklenen istemcileri oluşturmak için yapılandırılır.
- gRPC çağrıları taşıyıcı belirteci almak için kullanmalıdır
ITokenProvider
.
public interface ITokenProvider
{
Task<string> GetTokenAsync(CancellationToken cancellationToken);
}
public class AppTokenProvider : ITokenProvider
{
private string _token;
public async Task<string> GetTokenAsync(CancellationToken cancellationToken)
{
if (_token == null)
{
// App code to resolve the token here.
}
return _token;
}
}
services.AddScoped<ITokenProvider, AppTokenProvider>();
services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddCallCredentials(async (context, metadata, serviceProvider) =>
{
var provider = serviceProvider.GetRequiredService<ITokenProvider>();
var token = await provider.GetTokenAsync(context.CancellationToken);
metadata.Add("Authorization", $"Bearer {token}");
}));
Yukarıdaki kod:
- ve
AppTokenProvider
öğesini tanımlarITokenProvider
. Bu türler gRPC çağrıları için kimlik doğrulama belirtecini çözümlemeyi işler. AppTokenProvider
Türü kapsamlı bir yaşam süresi içinde DI'ye kaydeder.AppTokenProvider
belirteci önbelleğe alır, böylece yalnızca kapsamdaki ilk çağrının hesaplanması gerekir.- Türü istemci fabrikasına
GreeterClient
kaydeder. - Bu istemci için yapılandırılır
AddCallCredentials
. Temsilci her çağrı yapıldığında yürütülür ve tarafındanITokenProvider
döndürülen belirteci meta veriye ekler.
İstemci sertifikası kimlik doğrulaması
İstemci alternatif olarak kimlik doğrulaması için bir istemci sertifikası sağlayabilir. Sertifika kimlik doğrulaması , ASP.NET Core'a varmadan çok daha önce TLS düzeyinde gerçekleşir. İstek ASP.NET Core'a girdiğinde, istemci sertifikası kimlik doğrulama paketi sertifikayı bir ClaimsPrincipal
olarak çözümlemenize olanak tanır.
Not
Sunucuyu istemci sertifikalarını kabul etmek için yapılandırın. , IIS ve Azure'da Kestrelistemci sertifikalarını kabul etme hakkında bilgi için bkz . ASP.NET Core'da sertifika kimlik doğrulamasını yapılandırma.
.NET gRPC istemcisinde, daha sonra gRPC istemcisini oluşturmak için kullanılan istemci sertifikası eklenir HttpClientHandler
:
public Ticketer.TicketerClient CreateClientWithCert(
string baseAddress,
X509Certificate2 certificate)
{
// Add client cert to the handler
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate);
// Create the gRPC channel
var channel = GrpcChannel.ForAddress(baseAddress, new GrpcChannelOptions
{
HttpHandler = handler
});
return new Ticketer.TicketerClient(channel);
}
Diğer kimlik doğrulama mekanizmaları
Birçok ASP.NET Core destekli kimlik doğrulama mekanizması gRPC ile çalışır:
- Microsoft Entra Kimlik
- İstemci Sertifikası
- IdentityServer
- JWT Belirteci
- OAuth 2.0
- OpenID Connect
- WS-Federation
Sunucuda kimlik doğrulamasını yapılandırma hakkında daha fazla bilgi için bkz . ASP.NET Çekirdek kimlik doğrulaması.
gRPC istemcisini kimlik doğrulaması kullanacak şekilde yapılandırmak, kullandığınız kimlik doğrulama mekanizmasına bağlıdır. Önceki taşıyıcı belirteci ve istemci sertifikası örnekleri, gRPC istemcisinin gRPC çağrılarıyla kimlik doğrulama meta verilerini gönderecek şekilde yapılandırılmasının birkaç yolunu gösterir:
- Kesin olarak yazılan gRPC istemcileri dahili olarak kullanır
HttpClient
. Kimlik doğrulaması üzerinde HttpClientHandlerveya öğesine özel HttpMessageHandler örneklerHttpClient
eklenerek yapılandırılabilir. - Her gRPC çağrısının isteğe bağlı
CallOptions
bir bağımsız değişkeni vardır. Özel üst bilgiler seçeneğin üst bilgi koleksiyonu kullanılarak gönderilebilir.
Not
Windows Kimlik Doğrulaması (NTLM/Kerberos/Negotiate) gRPC ile kullanılamaz. gRPC HTTP/2 gerektirir ve HTTP/2, Windows Kimlik Doğrulamayı desteklemez.
Kullanıcılara hizmetlere ve hizmet yöntemlerine erişme yetkisi verme
Varsayılan olarak, bir hizmetteki tüm yöntemler kimliği doğrulanmamış kullanıcılar tarafından çağrılabilir. Kimlik doğrulaması gerektirmek için özniteliğini [Authorize]
hizmete uygulayın:
[Authorize]
public class TicketerService : Ticketer.TicketerBase
{
}
Yalnızca belirli yetkilendirme ilkeleriyle eşleşen kullanıcılara erişimi kısıtlamak için özniteliğin [Authorize]
oluşturucu bağımsız değişkenlerini ve özelliklerini kullanabilirsiniz. Örneğin, adlı MyAuthorizationPolicy
özel bir yetkilendirme ilkeniz varsa, yalnızca bu ilkeyle eşleşen kullanıcıların aşağıdaki kodu kullanarak hizmete erişebildiğinden emin olun:
[Authorize("MyAuthorizationPolicy")]
public class TicketerService : Ticketer.TicketerBase
{
}
Tek tek hizmet yöntemlerinde [Authorize]
de özniteliği uygulanabilir. Geçerli kullanıcı hem yönteme hem de sınıfa uygulanan ilkeler ile eşleşmiyorsa, çağırana bir hata döndürülür:
[Authorize]
public class TicketerService : Ticketer.TicketerBase
{
public override Task<AvailableTicketsResponse> GetAvailableTickets(
Empty request, ServerCallContext context)
{
// ... buy tickets for the current user ...
}
[Authorize("Administrators")]
public override Task<BuyTicketsResponse> RefundTickets(
BuyTicketsRequest request, ServerCallContext context)
{
// ... refund tickets (something only Administrators can do) ..
}
}
Yetkilendirme uzantısı yöntemleri
Authorizaton, ve RequireAuthorization
gibi AllowAnonymous
standart ASP.NET Core yetkilendirme uzantısı yöntemleri kullanılarak da denetlenebilir.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.MapGrpcService<TicketerService>().RequireAuthorization("Administrators");
app.Run();
Ek kaynaklar
ASP.NET Core