Minimal API uygulamalarında yanıt oluşturma
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.
En düşük uç noktalar aşağıdaki dönüş değeri türlerini destekler:
string
- Buna veValueTask<string>
dahildirTask<string>
.T
(Başka herhangi bir tür) - Ve'iValueTask<T>
içerirTask<T>
.IResult
based - Buna veValueTask<IResult>
dahildirTask<IResult>
.
string
dönüş değerleri
Davranış | İçerik Türü |
---|---|
Çerçeve, dizeyi doğrudan yanıta yazar. | text/plain |
Bir metin döndüren Hello world
aşağıdaki yol işleyicisini göz önünde bulundurun.
app.MapGet("/hello", () => "Hello World");
Durum 200
kodu content-Type üst bilgisi ve aşağıdaki içerikle text/plain
döndürülür.
Hello World
T
(Başka bir tür) değer döndürür
Davranış | İçerik Türü |
---|---|
JSON çerçevesi yanıtı seri hale getirmektedir. | application/json |
Dize özelliği içeren Message
anonim bir tür döndüren aşağıdaki yol işleyicisini göz önünde bulundurun.
app.MapGet("/hello", () => new { Message = "Hello World" });
Durum 200
kodu content-Type üst bilgisi ve aşağıdaki içerikle application/json
döndürülür.
{"message":"Hello World"}
IResult
dönüş değerleri
Davranış | İçerik Türü |
---|---|
Çerçeve IResult.ExecuteAsync'i çağırır. | Uygulama tarafından karar verilmiştir IResult . |
Arabirimi, IResult
HTTP uç noktasının sonucunu temsil eden bir sözleşme tanımlar. Statik Results sınıfı ve statik TypedResults , farklı yanıt türlerini temsil eden çeşitli IResult
nesneler oluşturmak için kullanılır.
TypedResults ve Sonuçlar
Results ve TypedResults statik sınıfları benzer sonuç yardımcı kümeleri sağlar. sınıfı TypedResults
, sınıfın türüne eşdeğerdir Results
. Ancak, yardımcıların Results
dönüş türü olurken IResult, her TypedResults
yardımcının dönüş türü uygulama türlerinden IResult
biridir. Aradaki fark, yardımcılar için Results
somut tür gerektiğinde ,örneğin birim testi için bir dönüştürme gerektiği anlamına gelir. Uygulama türleri ad alanında Microsoft.AspNetCore.Http.HttpResults tanımlanır.
Döndürmek TypedResults
yerine Results
aşağıdaki avantajlara sahiptir:
TypedResults
yardımcıları, kod okunabilirliğini, birim testini geliştirebilen ve çalışma zamanı hatalarının olasılığını azaltabilen kesin olarak belirlenmiş nesneler döndürür.- Uygulama türü , uç noktayı açıklamak üzere OpenAPI için yanıt türü meta verilerini otomatik olarak sağlar.
Beklenen JSON yanıtına sahip bir 200 OK
durum kodunun oluşturulduğu aşağıdaki uç noktayı göz önünde bulundurun.
app.MapGet("/hello", () => Results.Ok(new Message() { Text = "Hello World!" }))
.Produces<Message>();
Bu uç noktayı doğru bir şekilde belgelendirebilmek için uzantılar yöntemi Produces
çağrılır. Ancak, aşağıdaki kodda gösterildiği gibi yerine Results
kullanılırsa TypedResults
çağrısı Produces
yapılması gerekmez. TypedResults
otomatik olarak uç nokta için meta verileri sağlar.
app.MapGet("/hello2", () => TypedResults.Ok(new Message() { Text = "Hello World!" }));
Yanıt türünü açıklama hakkında daha fazla bilgi için bkz . Minimum API'lerde OpenAPI desteği.
Daha önce belirtildiği gibi, kullanırken TypedResults
bir dönüştürme gerekli değildir. Bir sınıf döndüren TypedResults
aşağıdaki en düşük API'yi göz önünde bulundurun
public static async Task<Ok<Todo[]>> GetAllTodos(TodoGroupDbContext database)
{
var todos = await database.Todos.ToArrayAsync();
return TypedResults.Ok(todos);
}
Aşağıdaki test tam somut türü denetler:
[Fact]
public async Task GetAllReturnsTodosFromDatabase()
{
// Arrange
await using var context = new MockDb().CreateDbContext();
context.Todos.Add(new Todo
{
Id = 1,
Title = "Test title 1",
Description = "Test description 1",
IsDone = false
});
context.Todos.Add(new Todo
{
Id = 2,
Title = "Test title 2",
Description = "Test description 2",
IsDone = true
});
await context.SaveChangesAsync();
// Act
var result = await TodoEndpointsV1.GetAllTodos(context);
//Assert
Assert.IsType<Ok<Todo[]>>(result);
Assert.NotNull(result.Value);
Assert.NotEmpty(result.Value);
Assert.Collection(result.Value, todo1 =>
{
Assert.Equal(1, todo1.Id);
Assert.Equal("Test title 1", todo1.Title);
Assert.False(todo1.IsDone);
}, todo2 =>
{
Assert.Equal(2, todo2.Id);
Assert.Equal("Test title 2", todo2.Title);
Assert.True(todo2.IsDone);
});
}
üzerindeki tüm yöntemler Results
imzalarını döndürdiğinden IResult
, derleyici tek bir uç noktadan farklı sonuçlar döndürürken istek temsilcisi dönüş türü olarak bunu otomatik olarak çıkarsar. TypedResults
bu tür temsilcilerden kullanımını Results<T1, TN>
gerektirir.
Döndürülen nesnelerin gerçek somut türleri farklı olsa bile, hem hem de Results.Ok
Results.NotFound
döndüren IResult
olarak bildirildiğinden aşağıdaki yöntem derlenir:
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
Aşağıdaki yöntem derlenmez, çünkü TypedResults.Ok
ve TypedResults.NotFound
farklı türler döndüren olarak bildirilir ve derleyici en iyi eşleşen türü çıkarsamaya çalışmaz:
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound());
kullanmak TypedResults
için dönüş türü tam olarak bildirilmelidir; zaman uyumsuz sarmalayıcı gerektirdiğinde Task<>
. Kullanmak TypedResults
daha ayrıntılıdır, ancak tür bilgilerinin statik olarak kullanılabilir olması ve bu nedenle OpenAPI'ye kendi kendini açıklayabilme özelliğine sahip olması için bu bir avantajdır:
app.MapGet("/todoitems/{id}", async Task<Results<Ok<Todo>, NotFound>> (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound());
Sonuçlar<TResult1, TResultN>
Aşağıdakiler yerine IResult
uç nokta işleyicisi dönüş türü olarak kullanınResults<TResult1, TResultN>
:
- Uç nokta işleyicisinden birden çok
IResult
uygulama türü döndürülür. - Statik
TypedResult
sınıf nesneleri oluşturmakIResult
için kullanılır.
Bu alternatif, genel birleşim türleri otomatik olarak uç nokta meta verilerini koruduğundan döndürmekten IResult
daha iyidir. Results<TResult1, TResultN>
Birleşim türleri örtük atama işleçleri uyguladığından, derleyici genel bağımsız değişkenlerde belirtilen türleri otomatik olarak birleşim türünün bir örneğine dönüştürebilir.
Bu, bir yol işleyicisinin aslında yalnızca bildirdiği sonuçları döndürdüğüne ilişkin derleme zamanı denetimi sağlamanın ek avantajına sahiptir. Derleme hatasıyla sonuçlanması için genel bağımsız değişkenlerden biri olarak bildirlenmemiş bir tür döndürülmeye Results<>
çalışılıyor.
değerinden büyük 999
olduğunda orderId
durum kodunun döndürüldiği aşağıdaki uç noktayı 400 BadRequest
göz önünde bulundurun. Aksi takdirde, beklenen içeriğe sahip bir 200 OK
oluşturur.
app.MapGet("/orders/{orderId}", IResult (int orderId)
=> orderId > 999 ? TypedResults.BadRequest() : TypedResults.Ok(new Order(orderId)))
.Produces(400)
.Produces<Order>();
Bu uç noktayı doğru bir şekilde belgelendirebilmek için uzantı yöntemi Produces
çağrılır. Ancak, TypedResults
yardımcı uç noktanın meta verilerini otomatik olarak içerdiğinden, aşağıdaki kodda gösterildiği gibi birleşim türünü döndürebilirsiniz Results<T1, Tn>
.
app.MapGet("/orders/{orderId}", Results<BadRequest, Ok<Order>> (int orderId)
=> orderId > 999 ? TypedResults.BadRequest() : TypedResults.Ok(new Order(orderId)));
Yerleşik sonuçlar
ve statik sınıflarında Results TypedResults ortak sonuç yardımcıları vardır. dönüş TypedResults
, döndürmek Results
için tercih edilir. Daha fazla bilgi için bkz . TypedResults vs Results.
Aşağıdaki bölümlerde ortak sonuç yardımcılarının kullanımı gösterilmektedir.
JSON
app.MapGet("/hello", () => Results.Json(new { Message = "Hello World" }));
WriteAsJsonAsync JSON döndürmenin alternatif bir yoludur:
app.MapGet("/", (HttpContext context) => context.Response.WriteAsJsonAsync
(new { Message = "Hello World" }));
Özel Durum Kodu
app.MapGet("/405", () => Results.StatusCode(405));
İç Sunucu Hatası
app.MapGet("/500", () => Results.InternalServerError("Something went wrong!"));
Yukarıdaki örnek 500 durum kodu döndürür.
Metin
app.MapGet("/text", () => Results.Text("This is some text"));
Akış
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var proxyClient = new HttpClient();
app.MapGet("/pokemon", async () =>
{
var stream = await proxyClient.GetStreamAsync("http://contoso/pokedex.json");
// Proxy the response as JSON
return Results.Stream(stream, "application/json");
});
app.Run();
Results.Stream
aşırı yüklemeler, arabelleğe almadan temel alınan HTTP yanıt akışına erişim sağlar. Aşağıdaki örnek, belirtilen görüntünün daha küçük bir boyutunu döndürmek için ImageSharp'ı kullanır:
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/process-image/{strImage}", (string strImage, HttpContext http, CancellationToken token) =>
{
http.Response.Headers.CacheControl = $"public,max-age={TimeSpan.FromHours(24).TotalSeconds}";
return Results.Stream(stream => ResizeImageAsync(strImage, stream, token), "image/jpeg");
});
async Task ResizeImageAsync(string strImage, Stream stream, CancellationToken token)
{
var strPath = $"wwwroot/img/{strImage}";
using var image = await Image.LoadAsync(strPath, token);
int width = image.Width / 2;
int height = image.Height / 2;
image.Mutate(x =>x.Resize(width, height));
await image.SaveAsync(stream, JpegFormat.Instance, cancellationToken: token);
}
Aşağıdaki örnek, Azure Blob depolamadan bir görüntü akışı yapar:
app.MapGet("/stream-image/{containerName}/{blobName}",
async (string blobName, string containerName, CancellationToken token) =>
{
var conStr = builder.Configuration["blogConStr"];
BlobContainerClient blobContainerClient = new BlobContainerClient(conStr, containerName);
BlobClient blobClient = blobContainerClient.GetBlobClient(blobName);
return Results.Stream(await blobClient.OpenReadAsync(cancellationToken: token), "image/jpeg");
});
Aşağıdaki örnek, Azure Blob'dan video akışı yapar:
// GET /stream-video/videos/earth.mp4
app.MapGet("/stream-video/{containerName}/{blobName}",
async (HttpContext http, CancellationToken token, string blobName, string containerName) =>
{
var conStr = builder.Configuration["blogConStr"];
BlobContainerClient blobContainerClient = new BlobContainerClient(conStr, containerName);
BlobClient blobClient = blobContainerClient.GetBlobClient(blobName);
var properties = await blobClient.GetPropertiesAsync(cancellationToken: token);
DateTimeOffset lastModified = properties.Value.LastModified;
long length = properties.Value.ContentLength;
long etagHash = lastModified.ToFileTime() ^ length;
var entityTag = new EntityTagHeaderValue('\"' + Convert.ToString(etagHash, 16) + '\"');
http.Response.Headers.CacheControl = $"public,max-age={TimeSpan.FromHours(24).TotalSeconds}";
return Results.Stream(await blobClient.OpenReadAsync(cancellationToken: token),
contentType: "video/mp4",
lastModified: lastModified,
entityTag: entityTag,
enableRangeProcessing: true);
});
Yönlendir
app.MapGet("/old-path", () => Results.Redirect("/new-path"));
Dosya
app.MapGet("/download", () => Results.File("myfile.text"));
HttpResult arabirimleri
Ad alanında Microsoft.AspNetCore.Http aşağıdaki arabirimler, filtre uygulamalarında yaygın olarak kullanılan bir desen olan çalışma zamanında türü algılamak IResult
için bir yol sağlar:
- IContentTypeHttpResult
- IFileHttpResult
- INestedHttpResult
- IStatusCodeHttpResult
- IValueHttpResult
- IValueHttpResult<TValue>
Aşağıda şu arabirimlerden birini kullanan bir filtre örneği verilmiştir:
app.MapGet("/weatherforecast", (int days) =>
{
if (days <= 0)
{
return Results.BadRequest();
}
var forecast = Enumerable.Range(1, days).Select(index =>
new WeatherForecast(DateTime.Now.AddDays(index), Random.Shared.Next(-20, 55), "Cool"))
.ToArray();
return Results.Ok(forecast);
}).
AddEndpointFilter(async (context, next) =>
{
var result = await next(context);
return result switch
{
IValueHttpResult<WeatherForecast[]> weatherForecastResult => new WeatherHttpResult(weatherForecastResult.Value),
_ => result
};
});
Daha fazla bilgi için bkz . Minimal API uygulamalarındaki filtreler ve IResult uygulama türleri.
Yanıtları özelleştirme
Uygulamalar özel IResult bir tür uygulayarak yanıtları denetleyebilir. Aşağıdaki kod, BIR HTML sonuç türü örneğidir:
using System.Net.Mime;
using System.Text;
static class ResultsExtensions
{
public static IResult Html(this IResultExtensions resultExtensions, string html)
{
ArgumentNullException.ThrowIfNull(resultExtensions);
return new HtmlResult(html);
}
}
class HtmlResult : IResult
{
private readonly string _html;
public HtmlResult(string html)
{
_html = html;
}
public Task ExecuteAsync(HttpContext httpContext)
{
httpContext.Response.ContentType = MediaTypeNames.Text.Html;
httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(_html);
return httpContext.Response.WriteAsync(_html);
}
}
Bu özel sonuçları daha bulunabilir hale getirmek için öğesine Microsoft.AspNetCore.Http.IResultExtensions bir uzantı yöntemi eklemenizi öneririz.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/html", () => Results.Extensions.Html(@$"<!doctype html>
<html>
<head><title>miniHTML</title></head>
<body>
<h1>Hello World</h1>
<p>The time on the server is {DateTime.Now:O}</p>
</body>
</html>"));
app.Run();
Ayrıca, özel IResult
bir tür arabirimini uygulayarak IEndpointMetadataProvider kendi ek açıklamasını sağlayabilir. Örneğin, aşağıdaki kod önceki türe HtmlResult
uç nokta tarafından oluşturulan yanıtı açıklayan bir ek açıklama ekler.
class HtmlResult : IResult, IEndpointMetadataProvider
{
private readonly string _html;
public HtmlResult(string html)
{
_html = html;
}
public Task ExecuteAsync(HttpContext httpContext)
{
httpContext.Response.ContentType = MediaTypeNames.Text.Html;
httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(_html);
return httpContext.Response.WriteAsync(_html);
}
public static void PopulateMetadata(MethodInfo method, EndpointBuilder builder)
{
builder.Metadata.Add(new ProducesHtmlMetadata());
}
}
ProducesHtmlMetadata
, oluşturulan yanıt içerik türünü text/html
ve durum kodunu 200 OK
tanımlayan bir uygulamasıdırIProducesResponseTypeMetadata.
internal sealed class ProducesHtmlMetadata : IProducesResponseTypeMetadata
{
public Type? Type => null;
public int StatusCode => 200;
public IEnumerable<string> ContentTypes { get; } = new[] { MediaTypeNames.Text.Html };
}
Alternatif bir yaklaşım, üretilen yanıtı açıklamak için öğesini Microsoft.AspNetCore.Mvc.ProducesAttribute kullanmaktır. Aşağıdaki kod yöntemini kullanacak ProducesAttribute
şekilde değiştirirPopulateMetadata
.
public static void PopulateMetadata(MethodInfo method, EndpointBuilder builder)
{
builder.Metadata.Add(new ProducesAttribute(MediaTypeNames.Text.Html));
}
JSON serileştirme seçeneklerini yapılandırma
Varsayılan olarak, minimum API uygulamaları JSON serileştirme ve seri durumdan çıkarma sırasında seçenekleri kullanır Web defaults
.
JSON serileştirme seçeneklerini genel olarak yapılandırma
Seçenekler, çağrılarak ConfigureHttpJsonOptionsbir uygulama için genel olarak yapılandırılabilir. Aşağıdaki örnek, ortak alanları ve JSON çıkışını biçimlendirmektedir.
var builder = WebApplication.CreateBuilder(args);
builder.Services.ConfigureHttpJsonOptions(options => {
options.SerializerOptions.WriteIndented = true;
options.SerializerOptions.IncludeFields = true;
});
var app = builder.Build();
app.MapPost("/", (Todo todo) => {
if (todo is not null) {
todo.Name = todo.NameField;
}
return todo;
});
app.Run();
class Todo {
public string? Name { get; set; }
public string? NameField;
public bool IsComplete { get; set; }
}
// If the request body contains the following JSON:
//
// {"nameField":"Walk dog", "isComplete":false}
//
// The endpoint returns the following JSON:
//
// {
// "name":"Walk dog",
// "nameField":"Walk dog",
// "isComplete":false
// }
Alanlar dahil olduğundan, yukarıdaki kod bunu okur NameField
ve çıkış JSON'una ekler.
Uç nokta için JSON serileştirme seçeneklerini yapılandırma
Bir uç nokta için serileştirme seçeneklerini yapılandırmak için aşağıdaki örnekte gösterildiği gibi çağırın Results.Json ve nesneye JsonSerializerOptions geçirin:
using System.Text.Json;
var app = WebApplication.Create();
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web)
{ WriteIndented = true };
app.MapGet("/", () =>
Results.Json(new Todo { Name = "Walk dog", IsComplete = false }, options));
app.Run();
class Todo
{
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
// The endpoint returns the following JSON:
//
// {
// "name":"Walk dog",
// "isComplete":false
// }
Alternatif olarak, nesnesini kabul JsonSerializerOptions eden bir aşırı yükleme WriteAsJsonAsync kullanın. Aşağıdaki örnek, çıkış JSON'unu biçimlendirmek için bu aşırı yüklemeyi kullanır:
using System.Text.Json;
var app = WebApplication.Create();
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web) {
WriteIndented = true };
app.MapGet("/", (HttpContext context) =>
context.Response.WriteAsJsonAsync<Todo>(
new Todo { Name = "Walk dog", IsComplete = false }, options));
app.Run();
class Todo
{
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
// The endpoint returns the following JSON:
//
// {
// "name":"Walk dog",
// "isComplete":false
// }
Ek Kaynaklar
En düşük uç noktalar aşağıdaki dönüş değeri türlerini destekler:
string
- Buna veValueTask<string>
dahildirTask<string>
.T
(Başka herhangi bir tür) - Ve'iValueTask<T>
içerirTask<T>
.IResult
based - Buna veValueTask<IResult>
dahildirTask<IResult>
.
string
dönüş değerleri
Davranış | İçerik Türü |
---|---|
Çerçeve, dizeyi doğrudan yanıta yazar. | text/plain |
Bir metin döndüren Hello world
aşağıdaki yol işleyicisini göz önünde bulundurun.
app.MapGet("/hello", () => "Hello World");
Durum 200
kodu content-Type üst bilgisi ve aşağıdaki içerikle text/plain
döndürülür.
Hello World
T
(Başka bir tür) değer döndürür
Davranış | İçerik Türü |
---|---|
JSON çerçevesi yanıtı seri hale getirmektedir. | application/json |
Dize özelliği içeren Message
anonim bir tür döndüren aşağıdaki yol işleyicisini göz önünde bulundurun.
app.MapGet("/hello", () => new { Message = "Hello World" });
Durum 200
kodu content-Type üst bilgisi ve aşağıdaki içerikle application/json
döndürülür.
{"message":"Hello World"}
IResult
dönüş değerleri
Davranış | İçerik Türü |
---|---|
Çerçeve IResult.ExecuteAsync'i çağırır. | Uygulama tarafından karar verilmiştir IResult . |
Arabirimi, IResult
HTTP uç noktasının sonucunu temsil eden bir sözleşme tanımlar. Statik Results sınıfı ve statik TypedResults , farklı yanıt türlerini temsil eden çeşitli IResult
nesneler oluşturmak için kullanılır.
TypedResults ve Sonuçlar
Results ve TypedResults statik sınıfları benzer sonuç yardımcı kümeleri sağlar. sınıfı TypedResults
, sınıfın türüne eşdeğerdir Results
. Ancak, yardımcıların Results
dönüş türü olurken IResult, her TypedResults
yardımcının dönüş türü uygulama türlerinden IResult
biridir. Aradaki fark, yardımcılar için Results
somut tür gerektiğinde ,örneğin birim testi için bir dönüştürme gerektiği anlamına gelir. Uygulama türleri ad alanında Microsoft.AspNetCore.Http.HttpResults tanımlanır.
Döndürmek TypedResults
yerine Results
aşağıdaki avantajlara sahiptir:
TypedResults
yardımcıları, kod okunabilirliğini, birim testini geliştirebilen ve çalışma zamanı hatalarının olasılığını azaltabilen kesin olarak belirlenmiş nesneler döndürür.- Uygulama türü , uç noktayı açıklamak üzere OpenAPI için yanıt türü meta verilerini otomatik olarak sağlar.
Beklenen JSON yanıtına sahip bir 200 OK
durum kodunun oluşturulduğu aşağıdaki uç noktayı göz önünde bulundurun.
app.MapGet("/hello", () => Results.Ok(new Message() { Text = "Hello World!" }))
.Produces<Message>();
Bu uç noktayı doğru bir şekilde belgelendirebilmek için uzantılar yöntemi Produces
çağrılır. Ancak, aşağıdaki kodda gösterildiği gibi yerine Results
kullanılırsa TypedResults
çağrısı Produces
yapılması gerekmez. TypedResults
otomatik olarak uç nokta için meta verileri sağlar.
app.MapGet("/hello2", () => TypedResults.Ok(new Message() { Text = "Hello World!" }));
Yanıt türünü açıklama hakkında daha fazla bilgi için bkz . Minimum API'lerde OpenAPI desteği.
Daha önce belirtildiği gibi, kullanırken TypedResults
bir dönüştürme gerekli değildir. Bir sınıf döndüren TypedResults
aşağıdaki en düşük API'yi göz önünde bulundurun
public static async Task<Ok<Todo[]>> GetAllTodos(TodoGroupDbContext database)
{
var todos = await database.Todos.ToArrayAsync();
return TypedResults.Ok(todos);
}
Aşağıdaki test tam somut türü denetler:
[Fact]
public async Task GetAllReturnsTodosFromDatabase()
{
// Arrange
await using var context = new MockDb().CreateDbContext();
context.Todos.Add(new Todo
{
Id = 1,
Title = "Test title 1",
Description = "Test description 1",
IsDone = false
});
context.Todos.Add(new Todo
{
Id = 2,
Title = "Test title 2",
Description = "Test description 2",
IsDone = true
});
await context.SaveChangesAsync();
// Act
var result = await TodoEndpointsV1.GetAllTodos(context);
//Assert
Assert.IsType<Ok<Todo[]>>(result);
Assert.NotNull(result.Value);
Assert.NotEmpty(result.Value);
Assert.Collection(result.Value, todo1 =>
{
Assert.Equal(1, todo1.Id);
Assert.Equal("Test title 1", todo1.Title);
Assert.False(todo1.IsDone);
}, todo2 =>
{
Assert.Equal(2, todo2.Id);
Assert.Equal("Test title 2", todo2.Title);
Assert.True(todo2.IsDone);
});
}
üzerindeki tüm yöntemler Results
imzalarını döndürdiğinden IResult
, derleyici tek bir uç noktadan farklı sonuçlar döndürürken istek temsilcisi dönüş türü olarak bunu otomatik olarak çıkarsar. TypedResults
bu tür temsilcilerden kullanımını Results<T1, TN>
gerektirir.
Döndürülen nesnelerin gerçek somut türleri farklı olsa bile, hem hem de Results.Ok
Results.NotFound
döndüren IResult
olarak bildirildiğinden aşağıdaki yöntem derlenir:
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
Aşağıdaki yöntem derlenmez, çünkü TypedResults.Ok
ve TypedResults.NotFound
farklı türler döndüren olarak bildirilir ve derleyici en iyi eşleşen türü çıkarsamaya çalışmaz:
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound());
kullanmak TypedResults
için dönüş türü tam olarak bildirilmelidir; zaman uyumsuz sarmalayıcı gerektirdiğinde Task<>
. Kullanmak TypedResults
daha ayrıntılıdır, ancak tür bilgilerinin statik olarak kullanılabilir olması ve bu nedenle OpenAPI'ye kendi kendini açıklayabilme özelliğine sahip olması için bu bir avantajdır:
app.MapGet("/todoitems/{id}", async Task<Results<Ok<Todo>, NotFound>> (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound());
Sonuçlar<TResult1, TResultN>
Aşağıdakiler yerine IResult
uç nokta işleyicisi dönüş türü olarak kullanınResults<TResult1, TResultN>
:
- Uç nokta işleyicisinden birden çok
IResult
uygulama türü döndürülür. - Statik
TypedResult
sınıf nesneleri oluşturmakIResult
için kullanılır.
Bu alternatif, genel birleşim türleri otomatik olarak uç nokta meta verilerini koruduğundan döndürmekten IResult
daha iyidir. Results<TResult1, TResultN>
Birleşim türleri örtük atama işleçleri uyguladığından, derleyici genel bağımsız değişkenlerde belirtilen türleri otomatik olarak birleşim türünün bir örneğine dönüştürebilir.
Bu, bir yol işleyicisinin aslında yalnızca bildirdiği sonuçları döndürdüğüne ilişkin derleme zamanı denetimi sağlamanın ek avantajına sahiptir. Derleme hatasıyla sonuçlanması için genel bağımsız değişkenlerden biri olarak bildirlenmemiş bir tür döndürülmeye Results<>
çalışılıyor.
değerinden büyük 999
olduğunda orderId
durum kodunun döndürüldiği aşağıdaki uç noktayı 400 BadRequest
göz önünde bulundurun. Aksi takdirde, beklenen içeriğe sahip bir 200 OK
oluşturur.
app.MapGet("/orders/{orderId}", IResult (int orderId)
=> orderId > 999 ? TypedResults.BadRequest() : TypedResults.Ok(new Order(orderId)))
.Produces(400)
.Produces<Order>();
Bu uç noktayı doğru bir şekilde belgelendirebilmek için uzantı yöntemi Produces
çağrılır. Ancak, TypedResults
yardımcı uç noktanın meta verilerini otomatik olarak içerdiğinden, aşağıdaki kodda gösterildiği gibi birleşim türünü döndürebilirsiniz Results<T1, Tn>
.
app.MapGet("/orders/{orderId}", Results<BadRequest, Ok<Order>> (int orderId)
=> orderId > 999 ? TypedResults.BadRequest() : TypedResults.Ok(new Order(orderId)));
Yerleşik sonuçlar
ve statik sınıflarında Results TypedResults ortak sonuç yardımcıları vardır. dönüş TypedResults
, döndürmek Results
için tercih edilir. Daha fazla bilgi için bkz . TypedResults vs Results.
Aşağıdaki bölümlerde ortak sonuç yardımcılarının kullanımı gösterilmektedir.
JSON
app.MapGet("/hello", () => Results.Json(new { Message = "Hello World" }));
WriteAsJsonAsync JSON döndürmenin alternatif bir yoludur:
app.MapGet("/", (HttpContext context) => context.Response.WriteAsJsonAsync
(new { Message = "Hello World" }));
Özel Durum Kodu
app.MapGet("/405", () => Results.StatusCode(405));
Metin
app.MapGet("/text", () => Results.Text("This is some text"));
Akış
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var proxyClient = new HttpClient();
app.MapGet("/pokemon", async () =>
{
var stream = await proxyClient.GetStreamAsync("http://contoso/pokedex.json");
// Proxy the response as JSON
return Results.Stream(stream, "application/json");
});
app.Run();
Results.Stream
aşırı yüklemeler, arabelleğe almadan temel alınan HTTP yanıt akışına erişim sağlar. Aşağıdaki örnek, belirtilen görüntünün daha küçük bir boyutunu döndürmek için ImageSharp'ı kullanır:
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/process-image/{strImage}", (string strImage, HttpContext http, CancellationToken token) =>
{
http.Response.Headers.CacheControl = $"public,max-age={TimeSpan.FromHours(24).TotalSeconds}";
return Results.Stream(stream => ResizeImageAsync(strImage, stream, token), "image/jpeg");
});
async Task ResizeImageAsync(string strImage, Stream stream, CancellationToken token)
{
var strPath = $"wwwroot/img/{strImage}";
using var image = await Image.LoadAsync(strPath, token);
int width = image.Width / 2;
int height = image.Height / 2;
image.Mutate(x =>x.Resize(width, height));
await image.SaveAsync(stream, JpegFormat.Instance, cancellationToken: token);
}
Aşağıdaki örnek, Azure Blob depolamadan bir görüntü akışı yapar:
app.MapGet("/stream-image/{containerName}/{blobName}",
async (string blobName, string containerName, CancellationToken token) =>
{
var conStr = builder.Configuration["blogConStr"];
BlobContainerClient blobContainerClient = new BlobContainerClient(conStr, containerName);
BlobClient blobClient = blobContainerClient.GetBlobClient(blobName);
return Results.Stream(await blobClient.OpenReadAsync(cancellationToken: token), "image/jpeg");
});
Aşağıdaki örnek, Azure Blob'dan video akışı yapar:
// GET /stream-video/videos/earth.mp4
app.MapGet("/stream-video/{containerName}/{blobName}",
async (HttpContext http, CancellationToken token, string blobName, string containerName) =>
{
var conStr = builder.Configuration["blogConStr"];
BlobContainerClient blobContainerClient = new BlobContainerClient(conStr, containerName);
BlobClient blobClient = blobContainerClient.GetBlobClient(blobName);
var properties = await blobClient.GetPropertiesAsync(cancellationToken: token);
DateTimeOffset lastModified = properties.Value.LastModified;
long length = properties.Value.ContentLength;
long etagHash = lastModified.ToFileTime() ^ length;
var entityTag = new EntityTagHeaderValue('\"' + Convert.ToString(etagHash, 16) + '\"');
http.Response.Headers.CacheControl = $"public,max-age={TimeSpan.FromHours(24).TotalSeconds}";
return Results.Stream(await blobClient.OpenReadAsync(cancellationToken: token),
contentType: "video/mp4",
lastModified: lastModified,
entityTag: entityTag,
enableRangeProcessing: true);
});
Yönlendir
app.MapGet("/old-path", () => Results.Redirect("/new-path"));
Dosya
app.MapGet("/download", () => Results.File("myfile.text"));
HttpResult arabirimleri
Ad alanında Microsoft.AspNetCore.Http aşağıdaki arabirimler, filtre uygulamalarında yaygın olarak kullanılan bir desen olan çalışma zamanında türü algılamak IResult
için bir yol sağlar:
- IContentTypeHttpResult
- IFileHttpResult
- INestedHttpResult
- IStatusCodeHttpResult
- IValueHttpResult
- IValueHttpResult<TValue>
Aşağıda şu arabirimlerden birini kullanan bir filtre örneği verilmiştir:
app.MapGet("/weatherforecast", (int days) =>
{
if (days <= 0)
{
return Results.BadRequest();
}
var forecast = Enumerable.Range(1, days).Select(index =>
new WeatherForecast(DateTime.Now.AddDays(index), Random.Shared.Next(-20, 55), "Cool"))
.ToArray();
return Results.Ok(forecast);
}).
AddEndpointFilter(async (context, next) =>
{
var result = await next(context);
return result switch
{
IValueHttpResult<WeatherForecast[]> weatherForecastResult => new WeatherHttpResult(weatherForecastResult.Value),
_ => result
};
});
Daha fazla bilgi için bkz . Minimal API uygulamalarındaki filtreler ve IResult uygulama türleri.
Yanıtları özelleştirme
Uygulamalar özel IResult bir tür uygulayarak yanıtları denetleyebilir. Aşağıdaki kod, BIR HTML sonuç türü örneğidir:
using System.Net.Mime;
using System.Text;
static class ResultsExtensions
{
public static IResult Html(this IResultExtensions resultExtensions, string html)
{
ArgumentNullException.ThrowIfNull(resultExtensions);
return new HtmlResult(html);
}
}
class HtmlResult : IResult
{
private readonly string _html;
public HtmlResult(string html)
{
_html = html;
}
public Task ExecuteAsync(HttpContext httpContext)
{
httpContext.Response.ContentType = MediaTypeNames.Text.Html;
httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(_html);
return httpContext.Response.WriteAsync(_html);
}
}
Bu özel sonuçları daha bulunabilir hale getirmek için öğesine Microsoft.AspNetCore.Http.IResultExtensions bir uzantı yöntemi eklemenizi öneririz.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/html", () => Results.Extensions.Html(@$"<!doctype html>
<html>
<head><title>miniHTML</title></head>
<body>
<h1>Hello World</h1>
<p>The time on the server is {DateTime.Now:O}</p>
</body>
</html>"));
app.Run();
Ayrıca, özel IResult
bir tür arabirimini uygulayarak IEndpointMetadataProvider kendi ek açıklamasını sağlayabilir. Örneğin, aşağıdaki kod önceki türe HtmlResult
uç nokta tarafından oluşturulan yanıtı açıklayan bir ek açıklama ekler.
class HtmlResult : IResult, IEndpointMetadataProvider
{
private readonly string _html;
public HtmlResult(string html)
{
_html = html;
}
public Task ExecuteAsync(HttpContext httpContext)
{
httpContext.Response.ContentType = MediaTypeNames.Text.Html;
httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(_html);
return httpContext.Response.WriteAsync(_html);
}
public static void PopulateMetadata(MethodInfo method, EndpointBuilder builder)
{
builder.Metadata.Add(new ProducesHtmlMetadata());
}
}
ProducesHtmlMetadata
, oluşturulan yanıt içerik türünü text/html
ve durum kodunu 200 OK
tanımlayan bir uygulamasıdırIProducesResponseTypeMetadata.
internal sealed class ProducesHtmlMetadata : IProducesResponseTypeMetadata
{
public Type? Type => null;
public int StatusCode => 200;
public IEnumerable<string> ContentTypes { get; } = new[] { MediaTypeNames.Text.Html };
}
Alternatif bir yaklaşım, üretilen yanıtı açıklamak için öğesini Microsoft.AspNetCore.Mvc.ProducesAttribute kullanmaktır. Aşağıdaki kod yöntemini kullanacak ProducesAttribute
şekilde değiştirirPopulateMetadata
.
public static void PopulateMetadata(MethodInfo method, EndpointBuilder builder)
{
builder.Metadata.Add(new ProducesAttribute(MediaTypeNames.Text.Html));
}
JSON serileştirme seçeneklerini yapılandırma
Varsayılan olarak, minimum API uygulamaları JSON serileştirme ve seri durumdan çıkarma sırasında seçenekleri kullanır Web defaults
.
JSON serileştirme seçeneklerini genel olarak yapılandırma
Seçenekler, çağrılarak ConfigureHttpJsonOptionsbir uygulama için genel olarak yapılandırılabilir. Aşağıdaki örnek, ortak alanları ve JSON çıkışını biçimlendirmektedir.
var builder = WebApplication.CreateBuilder(args);
builder.Services.ConfigureHttpJsonOptions(options => {
options.SerializerOptions.WriteIndented = true;
options.SerializerOptions.IncludeFields = true;
});
var app = builder.Build();
app.MapPost("/", (Todo todo) => {
if (todo is not null) {
todo.Name = todo.NameField;
}
return todo;
});
app.Run();
class Todo {
public string? Name { get; set; }
public string? NameField;
public bool IsComplete { get; set; }
}
// If the request body contains the following JSON:
//
// {"nameField":"Walk dog", "isComplete":false}
//
// The endpoint returns the following JSON:
//
// {
// "name":"Walk dog",
// "nameField":"Walk dog",
// "isComplete":false
// }
Alanlar dahil olduğundan, yukarıdaki kod bunu okur NameField
ve çıkış JSON'una ekler.
Uç nokta için JSON serileştirme seçeneklerini yapılandırma
Bir uç nokta için serileştirme seçeneklerini yapılandırmak için aşağıdaki örnekte gösterildiği gibi çağırın Results.Json ve nesneye JsonSerializerOptions geçirin:
using System.Text.Json;
var app = WebApplication.Create();
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web)
{ WriteIndented = true };
app.MapGet("/", () =>
Results.Json(new Todo { Name = "Walk dog", IsComplete = false }, options));
app.Run();
class Todo
{
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
// The endpoint returns the following JSON:
//
// {
// "name":"Walk dog",
// "isComplete":false
// }
Alternatif olarak, nesnesini kabul JsonSerializerOptions eden bir aşırı yükleme WriteAsJsonAsync kullanın. Aşağıdaki örnek, çıkış JSON'unu biçimlendirmek için bu aşırı yüklemeyi kullanır:
using System.Text.Json;
var app = WebApplication.Create();
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web) {
WriteIndented = true };
app.MapGet("/", (HttpContext context) =>
context.Response.WriteAsJsonAsync<Todo>(
new Todo { Name = "Walk dog", IsComplete = false }, options));
app.Run();
class Todo
{
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
// The endpoint returns the following JSON:
//
// {
// "name":"Walk dog",
// "isComplete":false
// }
Ek Kaynaklar
ASP.NET Core