Skip to content

Commit 4cc0df4

Browse files
Updated to ASP.NET Core 3.1, fixed HATEOAS and other bugs
1 parent 6371c3a commit 4cc0df4

File tree

10 files changed

+83
-71
lines changed

10 files changed

+83
-71
lines changed

SampleWebApiAspNetCore/Controllers/v1/FoodsController.cs

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class FoodsController : ControllerBase
2323
private readonly IMapper _mapper;
2424

2525
public FoodsController(
26-
IUrlHelper urlHelper,
26+
IUrlHelper urlHelper,
2727
IFoodRepository foodRepository,
2828
IMapper mapper)
2929
{
@@ -33,9 +33,9 @@ public FoodsController(
3333
}
3434

3535
[HttpGet(Name = nameof(GetAllFoods))]
36-
public ActionResult GetAllFoods([FromQuery] QueryParameters queryParameters)
36+
public ActionResult GetAllFoods(ApiVersion version, [FromQuery] QueryParameters queryParameters)
3737
{
38-
List<FoodItem> foodItems = _foodRepository.GetAll(queryParameters).ToList();
38+
List<FoodEntity> foodItems = _foodRepository.GetAll(queryParameters).ToList();
3939

4040
var allItemCount = _foodRepository.Count();
4141

@@ -50,9 +50,9 @@ public ActionResult GetAllFoods([FromQuery] QueryParameters queryParameters)
5050
Response.Headers.Add("X-Pagination",
5151
Newtonsoft.Json.JsonConvert.SerializeObject(paginationMetadata));
5252

53-
var links = CreateLinksForCollection(queryParameters, allItemCount);
53+
var links = CreateLinksForCollection(queryParameters, allItemCount, version);
5454

55-
var toReturn = foodItems.Select(x => ExpandSingleFoodItem(x));
55+
var toReturn = foodItems.Select(x => ExpandSingleFoodItem(x, version));
5656

5757
return Ok(new
5858
{
@@ -63,27 +63,27 @@ public ActionResult GetAllFoods([FromQuery] QueryParameters queryParameters)
6363

6464
[HttpGet]
6565
[Route("{id:int}", Name = nameof(GetSingleFood))]
66-
public ActionResult GetSingleFood(int id)
66+
public ActionResult GetSingleFood(ApiVersion version, int id)
6767
{
68-
FoodItem foodItem = _foodRepository.GetSingle(id);
68+
FoodEntity foodItem = _foodRepository.GetSingle(id);
6969

7070
if (foodItem == null)
7171
{
7272
return NotFound();
7373
}
7474

75-
return Ok(ExpandSingleFoodItem(foodItem));
75+
return Ok(ExpandSingleFoodItem(foodItem, version));
7676
}
7777

7878
[HttpPost(Name = nameof(AddFood))]
79-
public ActionResult<FoodItemDto> AddFood([FromBody] FoodCreateDto foodCreateDto)
79+
public ActionResult<FoodDto> AddFood(ApiVersion version, [FromBody] FoodCreateDto foodCreateDto)
8080
{
8181
if (foodCreateDto == null)
8282
{
8383
return BadRequest();
8484
}
8585

86-
FoodItem toAdd = _mapper.Map<FoodItem>(foodCreateDto);
86+
FoodEntity toAdd = _mapper.Map<FoodEntity>(foodCreateDto);
8787

8888
_foodRepository.Add(toAdd);
8989

@@ -92,21 +92,21 @@ public ActionResult<FoodItemDto> AddFood([FromBody] FoodCreateDto foodCreateDto)
9292
throw new Exception("Creating a fooditem failed on save.");
9393
}
9494

95-
FoodItem newFoodItem = _foodRepository.GetSingle(toAdd.Id);
95+
FoodEntity newFoodItem = _foodRepository.GetSingle(toAdd.Id);
9696

97-
return CreatedAtRoute(nameof(GetSingleFood), new { id = newFoodItem.Id },
98-
_mapper.Map<FoodItemDto>(newFoodItem));
97+
return CreatedAtRoute(nameof(GetSingleFood), new { version = version.ToString(), id = newFoodItem.Id },
98+
_mapper.Map<FoodDto>(newFoodItem));
9999
}
100100

101101
[HttpPatch("{id:int}", Name = nameof(PartiallyUpdateFood))]
102-
public ActionResult<FoodItemDto> PartiallyUpdateFood(int id, [FromBody] JsonPatchDocument<FoodUpdateDto> patchDoc)
102+
public ActionResult<FoodDto> PartiallyUpdateFood(int id, [FromBody] JsonPatchDocument<FoodUpdateDto> patchDoc)
103103
{
104104
if (patchDoc == null)
105105
{
106106
return BadRequest();
107107
}
108108

109-
FoodItem existingEntity = _foodRepository.GetSingle(id);
109+
FoodEntity existingEntity = _foodRepository.GetSingle(id);
110110

111111
if (existingEntity == null)
112112
{
@@ -124,21 +124,21 @@ public ActionResult<FoodItemDto> PartiallyUpdateFood(int id, [FromBody] JsonPatc
124124
}
125125

126126
_mapper.Map(foodUpdateDto, existingEntity);
127-
FoodItem updated = _foodRepository.Update(id, existingEntity);
127+
FoodEntity updated = _foodRepository.Update(id, existingEntity);
128128

129129
if (!_foodRepository.Save())
130130
{
131131
throw new Exception("Updating a fooditem failed on save.");
132132
}
133133

134-
return Ok(_mapper.Map<FoodItemDto>(updated));
134+
return Ok(_mapper.Map<FoodDto>(updated));
135135
}
136136

137137
[HttpDelete]
138138
[Route("{id:int}", Name = nameof(RemoveFood))]
139139
public ActionResult RemoveFood(int id)
140140
{
141-
FoodItem foodItem = _foodRepository.GetSingle(id);
141+
FoodEntity foodItem = _foodRepository.GetSingle(id);
142142

143143
if (foodItem == null)
144144
{
@@ -157,7 +157,7 @@ public ActionResult RemoveFood(int id)
157157

158158
[HttpPut]
159159
[Route("{id:int}", Name = nameof(UpdateFood))]
160-
public ActionResult<FoodItemDto> UpdateFood(int id, [FromBody]FoodUpdateDto foodUpdateDto)
160+
public ActionResult<FoodDto> UpdateFood(int id, [FromBody]FoodUpdateDto foodUpdateDto)
161161
{
162162
if (foodUpdateDto == null)
163163
{
@@ -180,16 +180,16 @@ public ActionResult<FoodItemDto> UpdateFood(int id, [FromBody]FoodUpdateDto food
180180
throw new Exception("Updating a fooditem failed on save.");
181181
}
182182

183-
return Ok(_mapper.Map<FoodItemDto>(existingFoodItem));
183+
return Ok(_mapper.Map<FoodDto>(existingFoodItem));
184184
}
185185

186186
[HttpGet("GetRandomMeal", Name = nameof(GetRandomMeal))]
187187
public ActionResult GetRandomMeal()
188188
{
189-
ICollection<FoodItem> foodItems = _foodRepository.GetRandomMeal();
189+
ICollection<FoodEntity> foodItems = _foodRepository.GetRandomMeal();
190190

191-
IEnumerable<FoodItemDto> dtos = foodItems
192-
.Select(x => _mapper.Map<FoodItemDto>(x));
191+
IEnumerable<FoodDto> dtos = foodItems
192+
.Select(x => _mapper.Map<FoodDto>(x));
193193

194194
var links = new List<LinkDto>();
195195

@@ -203,7 +203,7 @@ public ActionResult GetRandomMeal()
203203
});
204204
}
205205

206-
private List<LinkDto> CreateLinksForCollection(QueryParameters queryParameters, int totalCount)
206+
private List<LinkDto> CreateLinksForCollection(QueryParameters queryParameters, int totalCount, ApiVersion version)
207207
{
208208
var links = new List<LinkDto>();
209209

@@ -249,46 +249,54 @@ private List<LinkDto> CreateLinksForCollection(QueryParameters queryParameters,
249249
}), "previous", "GET"));
250250
}
251251

252+
var posturl = _urlHelper.Link(nameof(AddFood), new { version = version.ToString() });
253+
252254
links.Add(
253-
new LinkDto(_urlHelper.Link(nameof(AddFood), null),
255+
new LinkDto(posturl,
254256
"create_food",
255257
"POST"));
256258

257259
return links;
258260
}
259261

260-
private dynamic ExpandSingleFoodItem(FoodItem foodItem)
262+
private dynamic ExpandSingleFoodItem(FoodEntity foodItem, ApiVersion version)
261263
{
262-
var links = GetLinks(foodItem.Id);
263-
FoodItemDto item = _mapper.Map<FoodItemDto>(foodItem);
264+
var links = GetLinks(foodItem.Id, version);
265+
FoodDto item = _mapper.Map<FoodDto>(foodItem);
264266

265267
var resourceToReturn = item.ToDynamic() as IDictionary<string, object>;
266268
resourceToReturn.Add("links", links);
267269

268270
return resourceToReturn;
269271
}
270272

271-
private IEnumerable<LinkDto> GetLinks(int id)
273+
private IEnumerable<LinkDto> GetLinks(int id, ApiVersion version)
272274
{
273275
var links = new List<LinkDto>();
274276

277+
var getLink = _urlHelper.Link(nameof(GetSingleFood), new { version = version.ToString(), id = id });
278+
275279
links.Add(
276-
new LinkDto(_urlHelper.Link(nameof(GetSingleFood), new { id = id }),
277-
"self",
278-
"GET"));
280+
new LinkDto(getLink, "self", "GET"));
281+
282+
var deleteLink = _urlHelper.Link(nameof(RemoveFood), new { version = version.ToString(), id = id });
279283

280284
links.Add(
281-
new LinkDto(_urlHelper.Link(nameof(RemoveFood), new { id = id }),
285+
new LinkDto(deleteLink,
282286
"delete_food",
283287
"DELETE"));
284288

289+
var createLink = _urlHelper.Link(nameof(AddFood), new { version = version.ToString() });
290+
285291
links.Add(
286-
new LinkDto(_urlHelper.Link(nameof(AddFood), null),
292+
new LinkDto(createLink,
287293
"create_food",
288294
"POST"));
289295

296+
var updateLink = _urlHelper.Link(nameof(UpdateFood), new { version = version.ToString(), id = id });
297+
290298
links.Add(
291-
new LinkDto(_urlHelper.Link(nameof(UpdateFood), new { id = id }),
299+
new LinkDto(updateLink,
292300
"update_food",
293301
"PUT"));
294302

SampleWebApiAspNetCore/Dtos/FoodItemDto.cs renamed to SampleWebApiAspNetCore/Dtos/FoodDto.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace SampleWebApiAspNetCore.Dtos
44
{
5-
public class FoodItemDto
5+
public class FoodDto
66
{
77
public int Id { get; set; }
88
public string Name { get; set; }

SampleWebApiAspNetCore/Entities/FoodItem.cs renamed to SampleWebApiAspNetCore/Entities/FoodEntity.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace SampleWebApiAspNetCore.Entities
44
{
5-
public class FoodItem
5+
public class FoodEntity
66
{
77
public int Id { get; set; }
88
public string Name { get; set; }

SampleWebApiAspNetCore/MappingProfiles/FoodMappings.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ public class FoodMappings : Profile
88
{
99
public FoodMappings()
1010
{
11-
CreateMap<FoodItem, FoodItemDto>().ReverseMap();
12-
CreateMap<FoodItem, FoodUpdateDto>().ReverseMap();
13-
CreateMap<FoodItem, FoodCreateDto>().ReverseMap();
11+
CreateMap<FoodEntity, FoodDto>().ReverseMap();
12+
CreateMap<FoodEntity, FoodUpdateDto>().ReverseMap();
13+
CreateMap<FoodEntity, FoodCreateDto>().ReverseMap();
1414
}
1515
}
1616
}

SampleWebApiAspNetCore/Repositories/FoodDbContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public FoodDbContext(DbContextOptions<FoodDbContext> options)
1111

1212
}
1313

14-
public DbSet<FoodItem> FoodItems { get; set; }
14+
public DbSet<FoodEntity> FoodItems { get; set; }
1515

1616
}
1717
}

SampleWebApiAspNetCore/Repositories/FoodSqlRepository.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,31 @@ public FoodSqlRepository(FoodDbContext foodDbContext)
1717
_foodDbContext = foodDbContext;
1818
}
1919

20-
public FoodItem GetSingle(int id)
20+
public FoodEntity GetSingle(int id)
2121
{
2222
return _foodDbContext.FoodItems.FirstOrDefault(x => x.Id == id);
2323
}
2424

25-
public void Add(FoodItem item)
25+
public void Add(FoodEntity item)
2626
{
2727
_foodDbContext.FoodItems.Add(item);
2828
}
2929

3030
public void Delete(int id)
3131
{
32-
FoodItem foodItem = GetSingle(id);
32+
FoodEntity foodItem = GetSingle(id);
3333
_foodDbContext.FoodItems.Remove(foodItem);
3434
}
3535

36-
public FoodItem Update(int id, FoodItem item)
36+
public FoodEntity Update(int id, FoodEntity item)
3737
{
3838
_foodDbContext.FoodItems.Update(item);
3939
return item;
4040
}
4141

42-
public IQueryable<FoodItem> GetAll(QueryParameters queryParameters)
42+
public IQueryable<FoodEntity> GetAll(QueryParameters queryParameters)
4343
{
44-
IQueryable<FoodItem> _allItems = _foodDbContext.FoodItems.OrderBy(queryParameters.OrderBy,
44+
IQueryable<FoodEntity> _allItems = _foodDbContext.FoodItems.OrderBy(queryParameters.OrderBy,
4545
queryParameters.IsDescending());
4646

4747
if (queryParameters.HasQuery())
@@ -66,9 +66,9 @@ public bool Save()
6666
return (_foodDbContext.SaveChanges() >= 0);
6767
}
6868

69-
public ICollection<FoodItem> GetRandomMeal()
69+
public ICollection<FoodEntity> GetRandomMeal()
7070
{
71-
List<FoodItem> toReturn = new List<FoodItem>();
71+
List<FoodEntity> toReturn = new List<FoodEntity>();
7272

7373
toReturn.Add(GetRandomItem("Starter"));
7474
toReturn.Add(GetRandomItem("Main"));
@@ -77,7 +77,7 @@ public ICollection<FoodItem> GetRandomMeal()
7777
return toReturn;
7878
}
7979

80-
private FoodItem GetRandomItem(string type)
80+
private FoodEntity GetRandomItem(string type)
8181
{
8282
return _foodDbContext.FoodItems
8383
.Where(x => x.Type == type)

SampleWebApiAspNetCore/Repositories/IFoodRepository.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ namespace SampleWebApiAspNetCore.Repositories
77
{
88
public interface IFoodRepository
99
{
10-
FoodItem GetSingle(int id);
11-
void Add(FoodItem item);
10+
FoodEntity GetSingle(int id);
11+
void Add(FoodEntity item);
1212
void Delete(int id);
13-
FoodItem Update(int id, FoodItem item);
14-
IQueryable<FoodItem> GetAll(QueryParameters queryParameters);
13+
FoodEntity Update(int id, FoodEntity item);
14+
IQueryable<FoodEntity> GetAll(QueryParameters queryParameters);
1515

16-
ICollection<FoodItem> GetRandomMeal();
16+
ICollection<FoodEntity> GetRandomMeal();
1717
int Count();
1818

1919
bool Save();
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>netcoreapp3.0</TargetFramework>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
55
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
66
</PropertyGroup>
77

@@ -12,17 +12,17 @@
1212
<ItemGroup>
1313
<PackageReference Include="AutoMapper" Version="9.0.0" />
1414
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="7.0.0" />
15-
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0" />
16-
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="4.0.0-preview8.19405.7" />
17-
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="4.0.0-preview8.19405.7" />
18-
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.0.0" />
19-
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0" />
20-
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.0.0">
15+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="4.1.0" />
16+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="4.1.0" />
17+
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.0" />
18+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.0" />
19+
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0">
2120
<PrivateAssets>all</PrivateAssets>
2221
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2322
</PackageReference>
2423
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc3" />
2524
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.19" />
25+
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.0" />
2626
</ItemGroup>
2727

2828
</Project>

SampleWebApiAspNetCore/Services/SeedDataService.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ public class SeedDataService : ISeedDataService
99
{
1010
public async Task Initialize(FoodDbContext context)
1111
{
12-
context.FoodItems.Add(new FoodItem() { Calories = 1000, Type = "Starter", Name = "Lasagne", Created = DateTime.Now });
13-
context.FoodItems.Add(new FoodItem() { Calories = 1100, Type = "Main", Name = "Hamburger", Created = DateTime.Now });
14-
context.FoodItems.Add(new FoodItem() { Calories = 1200, Type = "Dessert", Name = "Spaghetti", Created = DateTime.Now });
15-
context.FoodItems.Add(new FoodItem() { Calories = 1300, Type = "Starter", Name = "Pizza", Created = DateTime.Now });
12+
context.FoodItems.Add(new FoodEntity() { Calories = 1000, Type = "Starter", Name = "Lasagne", Created = DateTime.Now });
13+
context.FoodItems.Add(new FoodEntity() { Calories = 1100, Type = "Main", Name = "Hamburger", Created = DateTime.Now });
14+
context.FoodItems.Add(new FoodEntity() { Calories = 1200, Type = "Dessert", Name = "Spaghetti", Created = DateTime.Now });
15+
context.FoodItems.Add(new FoodEntity() { Calories = 1300, Type = "Starter", Name = "Pizza", Created = DateTime.Now });
1616

1717
await context.SaveChangesAsync();
1818
}

0 commit comments

Comments
 (0)