.NET v7框架引入了路由组的概念,根据路径中的公共前缀将映射的端点分组在一起:
app.MapGroup("/public/todos").MapTodosApi();
现在,为了返回Created
响应(即POST
请求)的绝对路径,我需要在服务中使用该路由路径前缀。这个用例甚至在官方文档中有讨论:
在201 Created结果中不使用Location头的相对地址,还可以使用GroupRouteBuilder。GroupPrefix用于构造根相对地址
但是,GroupRouteBuilder
类不存在。只有一个RouteGroupBuilder
,但是它的实例没有成员GroupPrefix
。有什么建议如何得到前缀吗?
你链接的文档-尽管是预览文档-提到:
使用
GetPathByRouteValues
或GetUriByRouteValues
与routeName
有更多的选择。
关于链接生成的官方版本在这里。
它展示了如何注入和使用LinkGenerator (也包含上面提到的两个方法)和这样一个命名路由。
可以为端点指定名称,以便生成指向端点的url。使用命名端点可以避免在应用程序中硬编码路径
要将此应用到您所引用的示例中,
为检索Todo
项的路由命名,并在生成creatatedat url时使用它。
var group = app.MapGroup("todos");
group
.MapGet("/{id}", (int id) =>
{
// ...
return new Todo { Id = id };
})
.WithName("GetToDo");
group
.MapPost("/", (Todo todo, LinkGenerator linkGenerator) =>
{
// ...
var url = linkGenerator.GetPathByName("GetToDo", new { id = todo.Id });
return TypedResults.Created(url, todo);
});
在组合created-at url时使用组前缀的想法在GET (GET -item)端点的模式有一个额外的段的情况下是不够的,因为那个将不包括在内。您最终将组合多个硬编码字符串部分。
如果上面示例中的get-todo-item端点有一个额外的extra
段(如下例所示),那么id为123
的ToDo
项的创建地址url必须为
/todos/extra/123
将linkGenerator
与命名路由结合使用可以解决这个问题。
group
.MapGet("/extra/{id}", (int id) =>
{
// ...
return new Todo { Id = id };
})
.WithName("GetToDo");
我删除了我的另一个答案,因为它只显示了您提到的完整路由模式。我能够通过检查EndpointDataSource
s获得前缀,并返回到RouteGroupBuilder
(使用反射)。仍然不是很漂亮,但是如果你必须这样做,并且不想单独存储它,这可能是一个临时选项。
app.MapGroup("/public/todos").MapTodosApi();
app.Run();
public class Todo
{
public int Id { get; set; }
public string? Title { get; set; }
public bool IsComplete { get; set; }
}
public static class TodosApi
{
public static RouteGroupBuilder MapTodosApi(this RouteGroupBuilder group)
{
group.MapPost("/test", CreateTodo);
return group;
}
public static async Task<Created<Todo>> CreateTodo(Todo todo, IEnumerable<EndpointDataSource> endpointSources)
{
var compositeDataSource = (CompositeEndpointDataSource)(endpointSources.FirstOrDefault());
var datasource = compositeDataSource.DataSources.FirstOrDefault();
var nestedTypes = typeof(RouteGroupBuilder).GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Instance);
var routeGroupBuilderField = nestedTypes[0].GetField("_routeGroupBuilder", BindingFlags.NonPublic | BindingFlags.Instance);
var routeGroupValue = routeGroupBuilderField.GetValue(datasource);
var partialPrefixField = typeof(RouteGroupBuilder).GetField("_partialPrefix", BindingFlags.NonPublic | BindingFlags.Instance);
var partialPrefixValue = partialPrefixField.GetValue(routeGroupValue);
return TypedResults.Created($"{todo.Id}", todo);
}
}
partialPrefixValue
返回"/public/todos",而不是完整的"/public/todos/test"_partialPrefix
是RouteGroupBuilder
中的一个字段:https://github.com/dotnet/aspnetcore/blob/79e341268ac468cab6cfb09d6a1543103f66143c/src/Http/Routing/src/RouteGroupBuilder.cs