C#restapi,模型的子级应该是相同的类型,并且路由必须递归定义

C#restapi,模型的子级应该是相同的类型,并且路由必须递归定义,c#,.net,asp.net-core,routing,C#,.net,Asp.net Core,Routing,您好,我在.NET Core中遇到了架构问题 我有一个名为SContent的控制器,负责此路线-> [Route("api/content")] 如果您输入此路由/api/content/您将获得Id为Guid.Empty的所有内容 如果您输入此路由/api/content/{id},您将从第一级内容中获得特定内容(在这种情况下,MasterId必须等于Guid.Empty) 如果您输入此路由/api/content/{id}/children,您将获得父{id}的所有子级 现在我要做的是

您好,我在.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)}的子项


谢谢

恐怕没有可以满足您需求的内置线路。然而,编写自定义中间件很容易

简短答复:

  • 编写一个谓词,该谓词将设置
    Context.Items[“id”]
    Context.Items[“WantChildren”]
  • 将谓词传递给
    MapWhen()
    方法
  • 编写一个中间件,该中间件将根据
    Context.Items[“id”]
    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());
            });
        }
    );
    
    您还可以围绕中间件本身进行抽象,例如,创建一个工厂方法,该方法返回一个RequestDelegate,该方法可以轻松地与
    app.Run()
    一起使用:

    Func CreateContentChildrenMiddleware(Func操作){
    返回异步内容=>{
    var ccc=(ContentChildrenContext)(context.Items[“ContentChildrenContext”]);
    等待行动(ccc);
    };
    }
    

    最好的祝愿。

    对于每个不同的路由,如
    /api/content/{id}/children/{id2}/children
    ,您必须创建一个包含参数id.id2的函数。如果要创建新路由
    /api/content/{id}/children/{id2}/children/{id3}
    ,则必须创建一个包含参数id、id2、id3的新函数。所以,我认为,您不能在这里实现递归。可能是
    public class  ContentChildrenContext{
        public List<int> Ids {get;set;}
        public bool WantChildren{get;set;}
    }
    
    Func<Func<ContentChildrenContext,Task>,RequestDelegate> CreateContentChildrenMiddleware(Func<ContentChildrenContext,Task> action){
        return async content =>{
            var ccc= (ContentChildrenContext)(context.Items["ContentChildrenContext"]);
            await action(ccc);
        };
    }