Skip to content

Commit 8bca3ce

Browse files
added linkservice
1 parent 19e66d4 commit 8bca3ce

File tree

3 files changed

+217
-108
lines changed

3 files changed

+217
-108
lines changed

SampleWebApiAspNetCore/Controllers/v1/FoodsController.cs

Lines changed: 11 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using SampleWebApiAspNetCore.Entities;
1010
using SampleWebApiAspNetCore.Models;
1111
using SampleWebApiAspNetCore.Helpers;
12+
using SampleWebApiAspNetCore.Services;
1213
using System.Text.Json;
1314

1415
namespace SampleWebApiAspNetCore.v1.Controllers
@@ -22,15 +23,17 @@ public class FoodsController : ControllerBase
2223
private readonly IFoodRepository _foodRepository;
2324
private readonly IUrlHelper _urlHelper;
2425
private readonly IMapper _mapper;
26+
private readonly ILinkService<FoodsController> _linkService;
2527

2628
public FoodsController(
2729
IUrlHelper urlHelper,
2830
IFoodRepository foodRepository,
29-
IMapper mapper)
31+
IMapper mapper,
32+
ILinkService<FoodsController> linkService)
3033
{
3134
_foodRepository = foodRepository;
3235
_mapper = mapper;
33-
_urlHelper = urlHelper;
36+
_linkService = linkService;
3437
}
3538

3639
[HttpGet(Name = nameof(GetAllFoods))]
@@ -50,9 +53,8 @@ public ActionResult GetAllFoods(ApiVersion version, [FromQuery] QueryParameters
5053

5154
Response.Headers.Add("X-Pagination", JsonSerializer.Serialize(paginationMetadata));
5255

53-
var links = CreateLinksForCollection(queryParameters, allItemCount, version);
54-
55-
var toReturn = foodItems.Select(x => ExpandSingleFoodItem(x, version));
56+
var links = _linkService.CreateLinksForCollection(queryParameters, allItemCount, version);
57+
var toReturn = foodItems.Select(x => _linkService.ExpandSingleFoodItem(x, x.Id, version));
5658

5759
return Ok(new
5860
{
@@ -72,7 +74,9 @@ public ActionResult GetSingleFood(ApiVersion version, int id)
7274
return NotFound();
7375
}
7476

75-
return Ok(ExpandSingleFoodItem(foodItem, version));
77+
FoodDto item = _mapper.Map<FoodDto>(foodItem);
78+
79+
return Ok(_linkService.ExpandSingleFoodItem(item, item.Id, version));
7680
}
7781

7882
[HttpPost(Name = nameof(AddFood))]
@@ -189,8 +193,7 @@ public ActionResult GetRandomMeal()
189193
{
190194
ICollection<FoodEntity> foodItems = _foodRepository.GetRandomMeal();
191195

192-
IEnumerable<FoodDto> dtos = foodItems
193-
.Select(x => _mapper.Map<FoodDto>(x));
196+
IEnumerable<FoodDto> dtos = foodItems.Select(x => _mapper.Map<FoodDto>(x));
194197

195198
var links = new List<LinkDto>();
196199

@@ -203,105 +206,5 @@ public ActionResult GetRandomMeal()
203206
links = links
204207
});
205208
}
206-
207-
private List<LinkDto> CreateLinksForCollection(QueryParameters queryParameters, int totalCount, ApiVersion version)
208-
{
209-
var links = new List<LinkDto>();
210-
211-
// self
212-
links.Add(new LinkDto(_urlHelper.Link(nameof(GetAllFoods), new
213-
{
214-
pagecount = queryParameters.PageCount,
215-
page = queryParameters.Page,
216-
orderby = queryParameters.OrderBy
217-
}), "self", "GET"));
218-
219-
links.Add(new LinkDto(_urlHelper.Link(nameof(GetAllFoods), new
220-
{
221-
pagecount = queryParameters.PageCount,
222-
page = 1,
223-
orderby = queryParameters.OrderBy
224-
}), "first", "GET"));
225-
226-
links.Add(new LinkDto(_urlHelper.Link(nameof(GetAllFoods), new
227-
{
228-
pagecount = queryParameters.PageCount,
229-
page = queryParameters.GetTotalPages(totalCount),
230-
orderby = queryParameters.OrderBy
231-
}), "last", "GET"));
232-
233-
if (queryParameters.HasNext(totalCount))
234-
{
235-
links.Add(new LinkDto(_urlHelper.Link(nameof(GetAllFoods), new
236-
{
237-
pagecount = queryParameters.PageCount,
238-
page = queryParameters.Page + 1,
239-
orderby = queryParameters.OrderBy
240-
}), "next", "GET"));
241-
}
242-
243-
if (queryParameters.HasPrevious())
244-
{
245-
links.Add(new LinkDto(_urlHelper.Link(nameof(GetAllFoods), new
246-
{
247-
pagecount = queryParameters.PageCount,
248-
page = queryParameters.Page - 1,
249-
orderby = queryParameters.OrderBy
250-
}), "previous", "GET"));
251-
}
252-
253-
var posturl = _urlHelper.Link(nameof(AddFood), new { version = version.ToString() });
254-
255-
links.Add(
256-
new LinkDto(posturl,
257-
"create_food",
258-
"POST"));
259-
260-
return links;
261-
}
262-
263-
private dynamic ExpandSingleFoodItem(FoodEntity foodItem, ApiVersion version)
264-
{
265-
var links = GetLinks(foodItem.Id, version);
266-
FoodDto item = _mapper.Map<FoodDto>(foodItem);
267-
268-
var resourceToReturn = item.ToDynamic() as IDictionary<string, object>;
269-
resourceToReturn.Add("links", links);
270-
271-
return resourceToReturn;
272-
}
273-
274-
private IEnumerable<LinkDto> GetLinks(int id, ApiVersion version)
275-
{
276-
var links = new List<LinkDto>();
277-
278-
var getLink = _urlHelper.Link(nameof(GetSingleFood), new { version = version.ToString(), id = id });
279-
280-
links.Add(
281-
new LinkDto(getLink, "self", "GET"));
282-
283-
var deleteLink = _urlHelper.Link(nameof(RemoveFood), new { version = version.ToString(), id = id });
284-
285-
links.Add(
286-
new LinkDto(deleteLink,
287-
"delete_food",
288-
"DELETE"));
289-
290-
var createLink = _urlHelper.Link(nameof(AddFood), new { version = version.ToString() });
291-
292-
links.Add(
293-
new LinkDto(createLink,
294-
"create_food",
295-
"POST"));
296-
297-
var updateLink = _urlHelper.Link(nameof(UpdateFood), new { version = version.ToString(), id = id });
298-
299-
links.Add(
300-
new LinkDto(updateLink,
301-
"update_food",
302-
"PUT"));
303-
304-
return links;
305-
}
306209
}
307210
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using SampleWebApiAspNetCore.Models;
3+
4+
namespace SampleWebApiAspNetCore.Services
5+
{
6+
public interface ILinkService<T>
7+
{
8+
object ExpandSingleFoodItem(object resource, int identifier, ApiVersion version);
9+
10+
List<LinkDto> CreateLinksForCollection(QueryParameters queryParameters, int totalCount, ApiVersion version);
11+
}
12+
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using SampleWebApiAspNetCore.Models;
3+
using SampleWebApiAspNetCore.Helpers;
4+
using System.Reflection;
5+
6+
namespace SampleWebApiAspNetCore.Services
7+
{
8+
[AttributeUsage(AttributeTargets.Method)]
9+
public class LinkCollectionAttribute : Attribute
10+
{
11+
private string name;
12+
13+
public LinkCollectionAttribute(string name)
14+
{
15+
this.name = name;
16+
}
17+
}
18+
19+
[AttributeUsage(AttributeTargets.Method)]
20+
public class HateoasAttribute : Attribute
21+
{
22+
23+
}
24+
25+
public class LinkService<T> : ILinkService<T>
26+
{
27+
private readonly IUrlHelper _urlHelper;
28+
29+
public LinkService(IUrlHelper urlHelper)
30+
{
31+
_urlHelper = urlHelper;
32+
}
33+
34+
public List<LinkDto> CreateLinksForCollection(QueryParameters queryParameters, int totalCount, ApiVersion version)
35+
{
36+
Type myType = (typeof(T));
37+
MethodInfo[] methods = myType.GetMethods();
38+
39+
var links = new List<LinkDto>();
40+
var getAllMethodName = GetGetAllMethod(methods);
41+
42+
// self
43+
links.Add(new LinkDto(_urlHelper.Link(getAllMethodName, new
44+
{
45+
pagecount = queryParameters.PageCount,
46+
page = queryParameters.Page,
47+
orderby = queryParameters.OrderBy
48+
}), "self", "GET"));
49+
50+
links.Add(new LinkDto(_urlHelper.Link(getAllMethodName, new
51+
{
52+
pagecount = queryParameters.PageCount,
53+
page = 1,
54+
orderby = queryParameters.OrderBy
55+
}), "first", "GET"));
56+
57+
links.Add(new LinkDto(_urlHelper.Link(getAllMethodName, new
58+
{
59+
pagecount = queryParameters.PageCount,
60+
page = queryParameters.GetTotalPages(totalCount),
61+
orderby = queryParameters.OrderBy
62+
}), "last", "GET"));
63+
64+
if (queryParameters.HasNext(totalCount))
65+
{
66+
links.Add(new LinkDto(_urlHelper.Link(getAllMethodName, new
67+
{
68+
pagecount = queryParameters.PageCount,
69+
page = queryParameters.Page + 1,
70+
orderby = queryParameters.OrderBy
71+
}), "next", "GET"));
72+
}
73+
74+
if (queryParameters.HasPrevious())
75+
{
76+
links.Add(new LinkDto(_urlHelper.Link(getAllMethodName, new
77+
{
78+
pagecount = queryParameters.PageCount,
79+
page = queryParameters.Page - 1,
80+
orderby = queryParameters.OrderBy
81+
}), "previous", "GET"));
82+
}
83+
84+
var posturl = _urlHelper.Link(GetMethod(methods, typeof(HttpPostAttribute)), new { version = version.ToString() });
85+
86+
links.Add(
87+
new LinkDto(posturl,
88+
"create",
89+
"POST"));
90+
91+
return links;
92+
}
93+
94+
public object ExpandSingleFoodItem(object resource, int identifier, ApiVersion version)
95+
{
96+
var resourceToReturn = resource.ToDynamic() as IDictionary<string, object>;
97+
98+
var links = GetLinks(identifier, version);
99+
100+
resourceToReturn.Add("links", links);
101+
102+
return resourceToReturn;
103+
}
104+
105+
106+
private IEnumerable<LinkDto> GetLinks(int id, ApiVersion version)
107+
{
108+
Type myType = (typeof(T));
109+
MethodInfo[] methods = myType.GetMethods();
110+
var links = new List<LinkDto>();
111+
112+
var getLink = _urlHelper.Link(GetGetSingleMethod(methods), new { version = version.ToString(), id = id });
113+
links.Add(new LinkDto(getLink, "self", "GET"));
114+
115+
var deleteLink = _urlHelper.Link(GetMethod(methods, typeof(HttpDeleteAttribute)), new { version = version.ToString(), id = id });
116+
links.Add(
117+
new LinkDto(deleteLink,
118+
"delete",
119+
"DELETE"));
120+
121+
var createLink = _urlHelper.Link(GetMethod(methods, typeof(HttpPostAttribute)), new { version = version.ToString() });
122+
links.Add(
123+
new LinkDto(createLink,
124+
"create_food",
125+
"POST"));
126+
127+
var updateLink = _urlHelper.Link(GetMethod(methods, typeof(HttpPutAttribute)), new { version = version.ToString(), id = id });
128+
links.Add(
129+
new LinkDto(updateLink,
130+
"update_food",
131+
"PUT"));
132+
133+
return links;
134+
}
135+
136+
private string GetMethod(MethodInfo[] methods, Type type)
137+
{
138+
var method = methods.Where(m => m.GetCustomAttributes(type, false).Length > 0).ToArray().FirstOrDefault();
139+
140+
if (method is null)
141+
{
142+
return null;
143+
}
144+
145+
return method.Name;
146+
}
147+
148+
private string GetGetSingleMethod(MethodInfo[] methods)
149+
{
150+
var getMethods = methods.Where(m => m.GetCustomAttributes(typeof(HttpGetAttribute), false).Length > 0).ToArray();
151+
152+
if (getMethods.Length == 0)
153+
{
154+
return null;
155+
}
156+
157+
foreach (var getMethod in getMethods)
158+
{
159+
var routeAttribs = getMethod.GetCustomAttributes(typeof(RouteAttribute));
160+
161+
if(routeAttribs.Count() == 1)
162+
{
163+
return getMethod.Name;
164+
}
165+
}
166+
167+
168+
return null;
169+
}
170+
171+
private string GetGetAllMethod(MethodInfo[] methods)
172+
{
173+
var getMethods = methods.Where(m => m.GetCustomAttributes(typeof(HttpGetAttribute), false).Length > 0).ToArray();
174+
175+
if (getMethods.Length == 0)
176+
{
177+
return null;
178+
}
179+
180+
foreach (var getMethod in getMethods)
181+
{
182+
var routeAttribs = getMethod.GetCustomAttributes(typeof(RouteAttribute));
183+
184+
if (routeAttribs.Count() == 0)
185+
{
186+
return getMethod.Name;
187+
}
188+
}
189+
190+
191+
return null;
192+
}
193+
}
194+
}

0 commit comments

Comments
 (0)