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());
        );
    
);

这是一个有效的屏幕截图

进一步重构

为了更好的维护,您可以将IdsWantChildren 提取到单个类中,例如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 还是拆分?

Visual Studio项目REST api

C# Rest API 文件上传

节点js中的REST api,用于使用弹性搜索进行全文搜索

如何在.Net Core rest API响应中显示带两位小数的十进制数据类型

Rest API Post Json 使用带有两个参数的 C#