C# REST API,模型的子节点应该是同一类型,并且路由必须递归定义
Posted
技术标签:
【中文标题】C# REST API,模型的子节点应该是同一类型,并且路由必须递归定义【英文标题】:C# REST API, Children of model should be of same type, and routes must be recursively defined 【发布时间】:2018-07-31 06:24:27 【问题描述】:您好,我遇到了 .NET Core 的架构问题
我有一个名为 SContent 的控制器,带有这条路由 ->
[Route("api/content")]
如果你输入这条路由/api/content/你会得到Id为Guid.Empty的所有内容;
如果你输入这条路由 /api/content/id 你会从第一级内容中得到一个特定的内容(本例中MasterId必须等于Guid.Empty)
李>如果你输入这条路线 /api/content/id/children 你会得到父母 id 的所有孩子
现在我想做的是为以下任何一种情况创建一个递归路由:
/api/content/id/children/id2
/api/content/id/children/id2/children
/api/content/id/children/id2/children/id3
等等等等……
有可能做这样的事情吗? - 孩子属于同一类型的父母 - id(N) 应该始终是 id(N-1)
的子级谢谢
【问题讨论】:
对于每个不同的路由,如/api/content/id/children/id2/children
,您必须创建一个包含参数 id 的函数。身份证2。如果要创建新路由/api/content/id/children/id2/children/id3
,则必须创建一个包含参数 id、id2、id3 的新函数。所以,我认为,你不能在这里实现递归。
How to handle hierarchical routes in ASP.NET Web API?的可能重复
【参考方案1】:
恐怕没有内置路由可以满足你的需求。但是,编写自定义中间件很容易。
简短回答:
-
编写一个谓词来设置
Context.Items["Ids"]
和Context.Items["WantChildren"]
将谓词传递给MapWhen()
方法。
编写一个中间件,根据Context.Items["Ids"]
和Context.Items["WantChildren"]
处理逻辑以显示内容或获取其子项。
又快又脏的演示
这是一个快速而肮脏的演示:
app.MapWhen(
context =>
var path=context.Request.Path.ToString().ToLower();
if (path.EndsWith("/"))
path = path.Substring(0, path.Length-1);
if (!path.StartsWith("/api/content"))
return false;
var ids = new List<int>();
var wantChildren = false;
var match= Regex.Match(path,"/(?<id>\\d+)(?<children>/children)?");
while (match.Success)
var id = Convert.ToInt32(match.Groups["id"].Value); // todo: if throws an exception , ...
wantChildren= !String.IsNullOrEmpty(match.Groups["children"].Value);
ids.Add(id);
match = match.NextMatch();
context.Items["Ids"] = ids;
context.Items["WantChildren"] = wantChildren;
return true;
,
appBuilder =>
appBuilder.Run(async context =>
var ids = (List<int>)(context.Items["Ids"]);
var wantChildren = (bool)(context.Items["WantChildren"]);
// just a demo
// the code below should be replaced with those that you do with id list and whether you should display children
foreach (var id in ids)
await context.Response.WriteAsync(id.ToString());
await context.Response.WriteAsync(",");
await context.Response.WriteAsync(wantChildren.ToString());
);
);
这是一个有效的屏幕截图
进一步重构
为了更好的维护,您可以将Ids
和WantChildren
提取到单个类中,例如ContentChildrenContext
:
public class ContentChildrenContext
public List<int> Ids get;set;
public bool WantChildrenget;set;
您还可以围绕中间件本身进行抽象,例如,创建一个返回 RequestDelegate 的工厂方法,该方法可以轻松地与app.Run()
一起使用:
Func<Func<ContentChildrenContext,Task>,RequestDelegate> CreateContentChildrenMiddleware(Func<ContentChildrenContext,Task> action)
return async content =>
var ccc= (ContentChildrenContext)(context.Items["ContentChildrenContext"]);
await action(ccc);
;
最好的问候。
【讨论】:
以上是关于C# REST API,模型的子节点应该是同一类型,并且路由必须递归定义的主要内容,如果未能解决你的问题,请参考以下文章
我应该在同一台服务器上托管网站和 REST API 还是拆分?