Commit cad047da authored by Steve Smith's avatar Steve Smith

Fleshing out todoitem api and tests

Added ValidateModelAttribute
parent f6250567
......@@ -4,11 +4,14 @@ using System.Linq;
using System.Threading.Tasks;
using CleanArchitecture.Core.Entities;
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Web.ApiModels;
using CleanArchitecture.Web.Filters;
using Microsoft.AspNetCore.Mvc;
namespace CleanArchitecture.Web.Api
{
[Route("api/[controller]")]
[ValidateModel]
public class ToDoItemsController : Controller
{
private readonly IRepository<ToDoItem> _todoRepository;
......@@ -22,7 +25,8 @@ namespace CleanArchitecture.Web.Api
[HttpGet]
public IActionResult List()
{
var items = _todoRepository.List();
var items = _todoRepository.List()
.Select(item => ToDoItemDTO.FromToDoItem(item));
return Ok(items);
}
......@@ -30,8 +34,20 @@ namespace CleanArchitecture.Web.Api
[HttpGet("{id:int}")]
public IActionResult GetById(int id)
{
var items = _todoRepository.GetById(id);
return Ok(items);
var item = ToDoItemDTO.FromToDoItem(_todoRepository.GetById(id));
return Ok(item);
}
// POST: api/ToDoItems
public async Task<IActionResult> Post([FromBody] ToDoItemDTO item)
{
var todoItem = new ToDoItem()
{
Title = item.Title,
Description = item.Description
};
_todoRepository.Add(todoItem);
return Ok(ToDoItemDTO.FromToDoItem(todoItem));
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using CleanArchitecture.Core.Entities;
namespace CleanArchitecture.Web.ApiModels
{
// Note: doesn't expose events or behavior
public class ToDoItemDTO
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
public string Description { get; set; }
public bool IsDone { get; private set; }
public static ToDoItemDTO FromToDoItem(ToDoItem item)
{
return new ToDoItemDTO()
{
Id = item.Id,
Title = item.Title,
Description = item.Description,
IsDone = item.IsDone
};
}
}
}
......@@ -25,23 +25,29 @@ namespace CleanArchitecture.Web.Controllers
public IActionResult Populate()
{
if (_todoRepository.List().Any()) return Ok(0);
int recordsAdded = PopulateDatabase();
return Ok(recordsAdded);
}
public int PopulateDatabase()
{
if (_todoRepository.List().Any()) return 0;
_todoRepository.Add(new ToDoItem()
{
Title = "One",
Description = "The first item"
Title = "Get Sample Working",
Description = "Try to get the sample to build."
});
_todoRepository.Add(new ToDoItem()
{
Title = "Two",
Description = "The second item"
Title = "Review Solution",
Description = "Review the different projects in the solution and how they relate to one another."
});
_todoRepository.Add(new ToDoItem()
{
Title = "Three",
Description = "The three item"
Title = "Run and Review Tests",
Description = "Make sure all the tests run and review what they are doing."
});
return Ok(3);
return 3;
}
}
}
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace CleanArchitecture.Web.Filters
{
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(context.ModelState);
}
}
}
}
......@@ -5,6 +5,7 @@ using CleanArchitecture.Core.SharedKernel;
using CleanArchitecture.Infrastructure;
using CleanArchitecture.Infrastructure.Data;
using CleanArchitecture.Infrastructure.DomainEvents;
using CleanArchitecture.Web.ApiModels;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
......@@ -56,7 +57,7 @@ namespace CleanArchitecture.Web
_.ConnectImplementationsToTypesClosing(typeof(IHandle<>));
});
// ToDo: Add Registry Classes
// TODO: Add Registry Classes
// TODO: Move to Infrastucture Registry
config.For(typeof(IRepository<>)).Add(typeof(EfRepository<>));
......@@ -69,6 +70,40 @@ namespace CleanArchitecture.Web
services.AddTransient<IRepository<ToDoItem>, EfRepository<ToDoItem>>();
}
public void ConfigureTesting(IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
this.Configure(app, env, loggerFactory);
PopulateTestData(app);
//var authorRepository = app.ApplicationServices
// .GetService<IAuthorRepository>();
//Task.Run(() => PopulateSampleData(authorRepository));
}
private void PopulateTestData(IApplicationBuilder app)
{
var dbContext = app.ApplicationServices.GetService<AppDbContext>();
var toDos = dbContext.ToDoItems;
foreach (var item in toDos)
{
dbContext.Remove(item);
}
dbContext.SaveChanges();
dbContext.ToDoItems.Add(new ToDoItem()
{
Title = "Test Item 1",
Description = "Test Description One"
});
dbContext.ToDoItems.Add(new ToDoItem()
{
Title = "Test Item 2",
Description = "Test Description Two"
});
dbContext.SaveChanges();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
......
......@@ -6,7 +6,8 @@
<div class="col-md-6">
<h2>To Do Items</h2>
<ul>
<li><a asp-area="" asp-controller="ToDo" asp-action="Index">To Do Items</a></li>
<li><a asp-area="" asp-controller="ToDo" asp-action="Populate">Load Sample To Do Items</a></li>
<li><a asp-area="" asp-controller="ToDo" asp-action="Index">List To Do Items</a></li>
</ul>
</div>
<div class="col-md-6">
......
......@@ -6,6 +6,6 @@
<ul>
@foreach (var item in Model)
{
<li>@item.Title</li>
<li>@item.Title<br/>@item.Description</li>
}
</ul>
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
using CleanArchitecture.Infrastructure.Data;
using CleanArchitecture.Core.Entities;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using CleanArchitecture.Core.Events;
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Web;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Moq;
using Newtonsoft.Json;
namespace CleanArchitecture.Tests.Integration.Web
{
public class ApiToDoItemsControllerListShould
{
private readonly HttpClient _client;
public ApiToDoItemsControllerListShould()
{
_client = GetClient();
}
protected HttpClient GetClient()
{
var builder = new WebHostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseEnvironment("Testing"); // ensure ConfigureTesting is called in Startup
var server = new TestServer(builder);
var client = server.CreateClient();
// client always expects json results
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
[Fact]
public async Task ReturnTwoItems()
{
var response = await _client.GetAsync("/api/todoitems");
response.EnsureSuccessStatusCode();
var stringResponse = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<IEnumerable<ToDoItem>>(stringResponse).ToList();
Assert.Equal(2, result.Count());
Assert.Equal(1, result.Count(a => a.Title == "Test Item 1"));
Assert.Equal(1, result.Count(a => a.Title == "Test Item 2"));
}
}
}
\ No newline at end of file
......@@ -7,10 +7,13 @@
"NETStandard.Library": "1.6.0",
"xunit": "2.2.0-beta2-build3300",
"dotnet-test-xunit": "2.2.0-preview2-build1029",
"Microsoft.AspNetCore.TestHost": "1.0.0",
"Microsoft.EntityFrameworkCore": "1.0.0",
"Microsoft.EntityFrameworkCore.InMemory": "1.0.0",
"Newtonsoft.Json": "9.0.1",
"System.Diagnostics.TraceSource": "4.0.0",
"Moq": "4.6.25-alpha"
"Moq": "4.6.25-alpha",
"CleanArchitecture.Web": "1.0.0-*"
},
"tools": {
"Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment