Reputation: 13
Hi I am having an architectural problem with .NET Core
I have a controller called SContent with this route ->
[Route("api/content")]
if you enter this route /api/content/ You will get all contents where Id is Guid.Empty;
if you enter this route /api/content/{id} You will get a specific content from the first level of contents (MasterId must be equal to Guid.Empty in this case)
if you enter this route /api/content/{id}/children you will get all children of the parent {id}
now what I want to do is to create a recursive Route for any of the following cases:
/api/content/{id}/children/{id2}
/api/content/{id}/children/{id2}/children
/api/content/{id}/children/{id2}/children/{id3}
and so on and so on...
is it possible to do something like that? - children are of the same type of parent - {id(N)} should always be a child of {id(N-1)}
Thanks
Upvotes: 1
Views: 275
Reputation: 25380
I'm afraid that there is no built-in route that can meet your needs . However, writing a custom middleware is easy .
short answer :
Context.Items["Ids"]
and Context.Items["WantChildren"]
MapWhen()
method .Context.Items["Ids"]
and Context.Items["WantChildren"]
.Here's a quick and dirty demo :
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());
});
}
);
here's a screenshot that works
For better maintence , you can extract Ids
and WantChildren
to a single Class , for intance , ContentChildrenContext
:
public class ContentChildrenContext{
public List<int> Ids {get;set;}
public bool WantChildren{get;set;}
}
you can also make abstraction around the middleware itself , for example, create a factory method which returns a RequestDelegate that can be used easily with app.Run()
:
Func<Func<ContentChildrenContext,Task>,RequestDelegate> CreateContentChildrenMiddleware(Func<ContentChildrenContext,Task> action){
return async content =>{
var ccc= (ContentChildrenContext)(context.Items["ContentChildrenContext"]);
await action(ccc);
};
}
Best Regards .
Upvotes: 1