diff --git a/Controllers/TodoItemsController.cs b/Controllers/TodoItemsController.cs deleted file mode 100644 index 0ef138e7..00000000 --- a/Controllers/TodoItemsController.cs +++ /dev/null @@ -1,116 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using TodoApi.Models; - -namespace TodoApi.Controllers -{ - [Route("api/[controller]")] - [ApiController] - public class TodoItemsController : ControllerBase - { - private readonly TodoContext _context; - - public TodoItemsController(TodoContext context) - { - _context = context; - } - - [HttpGet] - public async Task>> GetTodoItems() - { - return await _context.TodoItems - .Select(x => ItemToDTO(x)) - .ToListAsync(); - } - - [HttpGet("{id}")] - public async Task> GetTodoItem(long id) - { - var todoItem = await _context.TodoItems.FindAsync(id); - - if (todoItem == null) - { - return NotFound(); - } - - return ItemToDTO(todoItem); - } - - [HttpPut("{id}")] - public async Task UpdateTodoItem(long id, TodoItemDTO todoItemDTO) - { - if (id != todoItemDTO.Id) - { - return BadRequest(); - } - - var todoItem = await _context.TodoItems.FindAsync(id); - if (todoItem == null) - { - return NotFound(); - } - - todoItem.Name = todoItemDTO.Name; - todoItem.IsComplete = todoItemDTO.IsComplete; - - try - { - await _context.SaveChangesAsync(); - } - catch (DbUpdateConcurrencyException) when (!TodoItemExists(id)) - { - return NotFound(); - } - - return NoContent(); - } - - [HttpPost] - public async Task> CreateTodoItem(TodoItemDTO todoItemDTO) - { - var todoItem = new TodoItem - { - IsComplete = todoItemDTO.IsComplete, - Name = todoItemDTO.Name - }; - - _context.TodoItems.Add(todoItem); - await _context.SaveChangesAsync(); - - return CreatedAtAction( - nameof(GetTodoItem), - new { id = todoItem.Id }, - ItemToDTO(todoItem)); - } - - [HttpDelete("{id}")] - public async Task DeleteTodoItem(long id) - { - var todoItem = await _context.TodoItems.FindAsync(id); - - if (todoItem == null) - { - return NotFound(); - } - - _context.TodoItems.Remove(todoItem); - await _context.SaveChangesAsync(); - - return NoContent(); - } - - private bool TodoItemExists(long id) => - _context.TodoItems.Any(e => e.Id == id); - - private static TodoItemDTO ItemToDTO(TodoItem todoItem) => - new TodoItemDTO - { - Id = todoItem.Id, - Name = todoItem.Name, - IsComplete = todoItem.IsComplete - }; - } -} diff --git a/README.md b/README.md index 466e41fd..caacadd9 100644 --- a/README.md +++ b/README.md @@ -1 +1,21 @@ -# TodoService \ No newline at end of file +# TodoService + +TASK DESCRIPTION: +1) Add swagger +2) Store list of tasks in SQL Server (initially InMemoryDB is used) +3) Do refactoring: extract Data Access Layer, Business Layer +4) Write unit tests for business operations + +Why I added CreateUpdateItemTodoDTO? +- To avoid the scenario when user types different ids in body and route parameter, simply avoiding that + +Why didn't I test all the methods in the service? +- methods I didn't test are too simple, thay only use mapper (which is tested) and call repo which calls EF, so it's like testing EF + +Possible scaling changes: +1) in case if TodoService will need to talk to more than one repo, it is good to add database service to store all of them +2) if project grows up it's good to separate DAL and BLL to separate projects, like I did with Tests + +P.S. +I've passed a real mapper instead of mocked one to service tests, because mapper is already tested and +mocking Automapper makes to sence since its aim is to reduce dumb mapping code diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj new file mode 100644 index 00000000..8fc3f147 --- /dev/null +++ b/Tests/Tests.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + diff --git a/Tests/TodoMapperTests.cs b/Tests/TodoMapperTests.cs new file mode 100644 index 00000000..1c6d1105 --- /dev/null +++ b/Tests/TodoMapperTests.cs @@ -0,0 +1,62 @@ +using AutoMapper; +using GeekStore.API.Core.Configurations; +using TodoApi.Models; +using TodoApiDTO.DTOs; + +namespace Tests +{ + [TestFixture] + public class TodoMapperTests + { + private readonly IMapper _mapper; + + public TodoMapperTests() + { + var mapperConfig = new MapperConfiguration(mc => + { + mc.AddProfile(new TodoProfile()); + }); + + _mapper = mapperConfig.CreateMapper(); + } + + [Test] + public void ModelToDtoTest() + { + var todo = new TodoItem { Id = 1, IsComplete = true, Name = "model", Secret = "secret" }; + var dto = _mapper.Map(todo); + + Assert.NotNull(dto); + Assert.IsTrue(dto.IsComplete); + Assert.AreEqual(todo.Id, dto.Id); + Assert.AreEqual(todo.Name, dto.Name); + } + + [Test] + public void DtoToModelTest() + { + var dto = new TodoItemDTO { Id = 1, IsComplete = true, Name = "model" }; + var todo = _mapper.Map(dto); + + Assert.NotNull(todo); + Assert.IsTrue(todo.IsComplete); + Assert.AreEqual(dto.Id, todo.Id); + Assert.AreEqual(todo.Name, dto.Name); + Assert.Null(todo.Secret); + } + + [Test] + public void CreateUpdateDtoToModelTest() + { + var dto = new CreateUpdateItemTodoDTO { Name = "postput", IsComplete = false }; + var todo = new TodoItem { Id = 1 }; + + _mapper.Map(dto, todo); + + Assert.IsFalse(todo.IsComplete); + Assert.AreEqual(dto.Name, todo.Name); + Assert.AreEqual(1, todo.Id); + + } + } +} \ No newline at end of file diff --git a/Tests/TodoServiceTests.cs b/Tests/TodoServiceTests.cs new file mode 100644 index 00000000..6d4685f8 --- /dev/null +++ b/Tests/TodoServiceTests.cs @@ -0,0 +1,79 @@ +using AutoMapper; +using GeekStore.API.Core.Configurations; +using Moq; +using TodoApi.Models; +using TodoApiDTO.ApiConstans; +using TodoApiDTO.DTOs; +using TodoApiDTO.Repositories.Interfaces; +using TodoApiDTO.Services; + +namespace Tests +{ + [TestFixture] + public class TodoServiceTests + { + private readonly IMapper _mapper; + private readonly TodoService _service; + private readonly Mock _repository; + + public TodoServiceTests() + { + _repository = new Mock(); + + var todoProfile = new TodoProfile(); + var configuration = new MapperConfiguration(cfg => cfg.AddProfile(todoProfile)); + _mapper = new Mapper(configuration); + + _service = new TodoService(_repository.Object, _mapper); + } + + [Test] + public void UpdateSuccessTest() + { + // Arrange + var dto = new CreateUpdateItemTodoDTO { Name = "update", IsComplete = false }; + _repository.Setup(r => r.Update(It.IsAny(), It.IsAny())) + .ReturnsAsync(ApiResponseStatus.Success); + + // Act + var result = _service.Update(123, dto); + + // Assert + Assert.AreEqual(ApiResponseStatus.Success, result.Result); + } + + [Test] + public void UpdateIncorrectIdTest() + { + // Arrange + var dto = new CreateUpdateItemTodoDTO { Name = "update", IsComplete = false }; + _repository.Setup(r => r.Update(It.IsAny(), It.IsAny())) + .ReturnsAsync(ApiResponseStatus.ItemDoesntExist); + + // Act + var result = _service.Update(123, null); + + // Assert + Assert.AreEqual(ApiResponseStatus.ItemDoesntExist, result.Result); + } + + [Test] + public void CreateSuccessTest() + { + // Arrange + var dto = new CreateUpdateItemTodoDTO { Name = "create", IsComplete = false }; + var expectedTodo = new TodoItem { Name = dto.Name, IsComplete = dto.IsComplete }; + _repository.Setup(r => r.Create(It.IsAny())) + .ReturnsAsync(expectedTodo); + + // Act + var result = _service.Create(dto); + + // Assert + var modelAfterUpdate = result.Result; + Assert.NotNull(modelAfterUpdate); + Assert.AreEqual(dto.IsComplete, modelAfterUpdate.IsComplete); + Assert.AreEqual(dto.Name, modelAfterUpdate.Name); + } + } +} diff --git a/Tests/Usings.cs b/Tests/Usings.cs new file mode 100644 index 00000000..cefced49 --- /dev/null +++ b/Tests/Usings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/TodoApiDTO.csproj b/TodoApiDTO.csproj deleted file mode 100644 index bba6f6af..00000000 --- a/TodoApiDTO.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - netcoreapp3.1 - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - diff --git a/TodoApiDTO/ApiConstans/ApiResponseStatus.cs b/TodoApiDTO/ApiConstans/ApiResponseStatus.cs new file mode 100644 index 00000000..9153ed4d --- /dev/null +++ b/TodoApiDTO/ApiConstans/ApiResponseStatus.cs @@ -0,0 +1,12 @@ +using System.ComponentModel; + +namespace TodoApiDTO.ApiConstans +{ + public enum ApiResponseStatus + { + [Description("Success")] + Success, + [Description("Item does not exist")] + ItemDoesntExist, + } +} diff --git a/TodoApiDTO/Controllers/TodoItemsController.cs b/TodoApiDTO/Controllers/TodoItemsController.cs new file mode 100644 index 00000000..45acba81 --- /dev/null +++ b/TodoApiDTO/Controllers/TodoItemsController.cs @@ -0,0 +1,71 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using TodoApiDTO.ApiConstans; +using TodoApiDTO.DTOs; +using TodoApiDTO.Extentions; +using TodoApiDTO.Services.Interfaces; + +namespace TodoApi.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class TodoItemsController : ControllerBase + { + private readonly ITodoService _todoService; + + public TodoItemsController(ITodoService todoService) + { + _todoService = todoService; + } + + [HttpGet] + public async Task GetAll() => Ok(await _todoService.GetAll()); + + [HttpGet("{id}")] + public async Task Get(long id) + { + var todoItem = await _todoService.Get(id); + + if (todoItem == null) + { + return NotFound(ApiResponseStatus.ItemDoesntExist.GetEnumDescription()); + } + + return Ok(todoItem); + } + + [HttpPut("{id}")] + public async Task Update(long id, CreateUpdateItemTodoDTO createUpdateDTO) + { + var response = await _todoService.Update(id, createUpdateDTO); + + if (response == ApiResponseStatus.ItemDoesntExist) + { + return NotFound(response.GetEnumDescription()); + } + + return NoContent(); + } + + [HttpPost] + public async Task Create(CreateUpdateItemTodoDTO createUpdateDTO) + { + var todo = await _todoService.Create(createUpdateDTO); + + return CreatedAtAction(nameof(Get), new { id = todo.Id }, todo); + } + + [HttpDelete("{id}")] + public async Task Delete(long id) + { + var response = await _todoService.Delete(id); + + if (response == ApiResponseStatus.ItemDoesntExist) + { + return NotFound(response.GetEnumDescription()); + } + + return NoContent(); + } + } +} diff --git a/TodoApiDTO/DTOs/CreateUpdateItemTodoDTO.cs b/TodoApiDTO/DTOs/CreateUpdateItemTodoDTO.cs new file mode 100644 index 00000000..b3b6d683 --- /dev/null +++ b/TodoApiDTO/DTOs/CreateUpdateItemTodoDTO.cs @@ -0,0 +1,8 @@ +namespace TodoApiDTO.DTOs +{ + public class CreateUpdateItemTodoDTO + { + public string Name { get; set; } + public bool IsComplete { get; set; } + } +} diff --git a/Models/TodoItemDTO.cs b/TodoApiDTO/DTOs/TodoItemDTO.cs similarity index 72% rename from Models/TodoItemDTO.cs rename to TodoApiDTO/DTOs/TodoItemDTO.cs index e66a500a..5ce0e5ce 100644 --- a/Models/TodoItemDTO.cs +++ b/TodoApiDTO/DTOs/TodoItemDTO.cs @@ -1,11 +1,9 @@ -namespace TodoApi.Models +namespace TodoApiDTO.DTOs { - #region snippet public class TodoItemDTO { public long Id { get; set; } public string Name { get; set; } public bool IsComplete { get; set; } } - #endregion } diff --git a/TodoApiDTO/Extentions/EnumDescriptionExtention.cs b/TodoApiDTO/Extentions/EnumDescriptionExtention.cs new file mode 100644 index 00000000..a1ffacde --- /dev/null +++ b/TodoApiDTO/Extentions/EnumDescriptionExtention.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel; + +namespace TodoApiDTO.Extentions +{ + public static class EnumDescriptionExtention + { + public static string GetEnumDescription(this Enum enumValue) + { + var field = enumValue.GetType().GetField(enumValue.ToString()); + if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attribute) + { + return attribute.Description; + } + throw new ArgumentException("Item not found.", nameof(enumValue)); + } + } +} diff --git a/TodoApiDTO/Mappers/TodoProfile.cs b/TodoApiDTO/Mappers/TodoProfile.cs new file mode 100644 index 00000000..200d016e --- /dev/null +++ b/TodoApiDTO/Mappers/TodoProfile.cs @@ -0,0 +1,18 @@ +using AutoMapper; +using TodoApi.Models; +using TodoApiDTO.DTOs; + +namespace GeekStore.API.Core.Configurations +{ + public class TodoProfile : Profile + { + public TodoProfile() + { + CreateMap() + .ForMember(x => x.Secret, opt => opt.Ignore()) + .ReverseMap(); + + CreateMap(); + } + } +} \ No newline at end of file diff --git a/Models/TodoContext.cs b/TodoApiDTO/Models/TodoContext.cs similarity index 100% rename from Models/TodoContext.cs rename to TodoApiDTO/Models/TodoContext.cs diff --git a/Models/TodoItem.cs b/TodoApiDTO/Models/TodoItem.cs similarity index 87% rename from Models/TodoItem.cs rename to TodoApiDTO/Models/TodoItem.cs index 1f6e5465..8b76633b 100644 --- a/Models/TodoItem.cs +++ b/TodoApiDTO/Models/TodoItem.cs @@ -1,6 +1,5 @@ namespace TodoApi.Models { - #region snippet public class TodoItem { public long Id { get; set; } @@ -8,5 +7,4 @@ public class TodoItem public bool IsComplete { get; set; } public string Secret { get; set; } } - #endregion } \ No newline at end of file diff --git a/Program.cs b/TodoApiDTO/Program.cs similarity index 74% rename from Program.cs rename to TodoApiDTO/Program.cs index b27ac16a..4fe9a571 100644 --- a/Program.cs +++ b/TodoApiDTO/Program.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; namespace TodoApi { diff --git a/Properties/launchSettings.json b/TodoApiDTO/Properties/launchSettings.json similarity index 100% rename from Properties/launchSettings.json rename to TodoApiDTO/Properties/launchSettings.json diff --git a/TodoApiDTO/Repositories/Interfaces/ITodoRepository.cs b/TodoApiDTO/Repositories/Interfaces/ITodoRepository.cs new file mode 100644 index 00000000..ecfb1100 --- /dev/null +++ b/TodoApiDTO/Repositories/Interfaces/ITodoRepository.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using TodoApi.Models; +using TodoApiDTO.ApiConstans; + +namespace TodoApiDTO.Repositories.Interfaces +{ + public interface ITodoRepository + { + public Task> GetAll(); + public Task Get(long id); + public Task Update(long id, TodoItem todoItem); + public Task Create(TodoItem todoItem); + public Task Delete(long id); + } +} diff --git a/TodoApiDTO/Repositories/TodoRepository.cs b/TodoApiDTO/Repositories/TodoRepository.cs new file mode 100644 index 00000000..bdd116fa --- /dev/null +++ b/TodoApiDTO/Repositories/TodoRepository.cs @@ -0,0 +1,75 @@ +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using TodoApi.Models; +using TodoApiDTO.ApiConstans; +using TodoApiDTO.Repositories.Interfaces; + +namespace TodoApiDTO.Repositories +{ + public class TodoRepository : ITodoRepository + { + private readonly TodoContext _context; + + public TodoRepository(TodoContext context) + { + _context = context; + } + + public async Task> GetAll() + { + return await _context.TodoItems.ToListAsync(); + } + + public async Task Get(long id) + { + return await _context.TodoItems.FindAsync(id); + } + + public async Task Update(long id, TodoItem model) + { + try + { + var todoItem = await Get(id); + if (todoItem == null) + { + return ApiResponseStatus.ItemDoesntExist; + } + todoItem.Name = model.Name; + todoItem.IsComplete = model.IsComplete; + + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) when (!TodoItemExists(id)) + { + return ApiResponseStatus.ItemDoesntExist; + } + return ApiResponseStatus.Success; + } + public async Task Create(TodoItem model) + { + _context.TodoItems.Add(model); + await _context.SaveChangesAsync(); + + return model; + } + + public async Task Delete(long id) + { + var todoItem = await Get(id); + + if (todoItem == null) + { + return ApiResponseStatus.ItemDoesntExist; + } + + _context.TodoItems.Remove(todoItem); + await _context.SaveChangesAsync(); + + return ApiResponseStatus.Success; + } + + private bool TodoItemExists(long id) => _context.TodoItems.Any(todo => todo.Id == id); + } +} diff --git a/TodoApiDTO/Services/Interfaces/ITodoService.cs b/TodoApiDTO/Services/Interfaces/ITodoService.cs new file mode 100644 index 00000000..7b8dc08d --- /dev/null +++ b/TodoApiDTO/Services/Interfaces/ITodoService.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using TodoApiDTO.ApiConstans; +using TodoApiDTO.DTOs; + +namespace TodoApiDTO.Services.Interfaces +{ + public interface ITodoService + { + public Task> GetAll(); + public Task Get(long id); + public Task Update(long id, CreateUpdateItemTodoDTO createUpdateItemTodo); + public Task Create(CreateUpdateItemTodoDTO createUpdateItemTodo); + public Task Delete(long id); + } +} diff --git a/TodoApiDTO/Services/TodoService.cs b/TodoApiDTO/Services/TodoService.cs new file mode 100644 index 00000000..73804406 --- /dev/null +++ b/TodoApiDTO/Services/TodoService.cs @@ -0,0 +1,54 @@ +using AutoMapper; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using TodoApi.Models; +using TodoApiDTO.ApiConstans; +using TodoApiDTO.DTOs; +using TodoApiDTO.Repositories.Interfaces; +using TodoApiDTO.Services.Interfaces; + +namespace TodoApiDTO.Services +{ + public class TodoService : ITodoService + { + private readonly ITodoRepository _repository; + private readonly IMapper _mapper; + + public TodoService(ITodoRepository repository, IMapper mapper) + { + _repository = repository; + _mapper = mapper; + } + + public async Task> GetAll() + { + var todos = await _repository.GetAll(); + return todos.Select(todo => _mapper.Map(todo)); + } + + public async Task Get(long id) + { + return _mapper.Map(await _repository.Get(id)); + } + + public async Task Update(long id, CreateUpdateItemTodoDTO createUpdateDTO) + { + var todoItem = _mapper.Map(createUpdateDTO); + + return await _repository.Update(id, todoItem); + } + + public async Task Create(CreateUpdateItemTodoDTO createUpdateDTO) + { + var todoItem = _mapper.Map(createUpdateDTO); + + return _mapper.Map(await _repository.Create(todoItem)); + } + + public async Task Delete(long id) + { + return await _repository.Delete(id); + } + } +} diff --git a/Startup.cs b/TodoApiDTO/Startup.cs similarity index 53% rename from Startup.cs rename to TodoApiDTO/Startup.cs index bbfbc83d..b2b5b5cc 100644 --- a/Startup.cs +++ b/TodoApiDTO/Startup.cs @@ -1,17 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; using TodoApi.Models; +using Microsoft.OpenApi.Models; +using TodoApiDTO.Services.Interfaces; +using TodoApiDTO.Services; +using TodoApiDTO.Repositories; +using TodoApiDTO.Repositories.Interfaces; +using AutoMapper; +using GeekStore.API.Core.Configurations; namespace TodoApi { @@ -27,9 +27,25 @@ public Startup(IConfiguration configuration) // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddDbContext(opt => - opt.UseInMemoryDatabase("TodoList")); services.AddControllers(); + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Todo API", Version = "v1" }); + }); + + services.AddDbContext(options => + options.UseSqlServer(Configuration.GetConnectionString("TodosDatabase"))); + + var mapperConfig = new MapperConfiguration(mc => + { + mc.AddProfile(new TodoProfile()); + }); + + IMapper mapper = mapperConfig.CreateMapper(); + services.AddSingleton(mapper); + + services.AddScoped(); + services.AddScoped(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -50,6 +66,13 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { endpoints.MapControllers(); }); + + app.UseSwagger(); + + app.UseSwaggerUI(c => + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "TodoAPI"); + }); } } } diff --git a/TodoApiDTO/TodoApiDTO.csproj b/TodoApiDTO/TodoApiDTO.csproj new file mode 100644 index 00000000..544c810e --- /dev/null +++ b/TodoApiDTO/TodoApiDTO.csproj @@ -0,0 +1,23 @@ + + + + netcoreapp3.1 + + + + + + + + + + + + + + + + + + + diff --git a/TodoApiDTO.sln b/TodoApiDTO/TodoApiDTO.sln similarity index 66% rename from TodoApiDTO.sln rename to TodoApiDTO/TodoApiDTO.sln index e49c182b..a786fd7b 100644 --- a/TodoApiDTO.sln +++ b/TodoApiDTO/TodoApiDTO.sln @@ -1,10 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30002.166 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33801.468 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoApiDTO", "TodoApiDTO.csproj", "{623124F9-F5BA-42DD-BC26-A1720774229C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "..\Tests\Tests.csproj", "{FBA88543-0422-4044-B1C3-FC7ECFC14AA9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {623124F9-F5BA-42DD-BC26-A1720774229C}.Debug|Any CPU.Build.0 = Debug|Any CPU {623124F9-F5BA-42DD-BC26-A1720774229C}.Release|Any CPU.ActiveCfg = Release|Any CPU {623124F9-F5BA-42DD-BC26-A1720774229C}.Release|Any CPU.Build.0 = Release|Any CPU + {FBA88543-0422-4044-B1C3-FC7ECFC14AA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FBA88543-0422-4044-B1C3-FC7ECFC14AA9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBA88543-0422-4044-B1C3-FC7ECFC14AA9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FBA88543-0422-4044-B1C3-FC7ECFC14AA9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/appsettings.Development.json b/TodoApiDTO/appsettings.Development.json similarity index 54% rename from appsettings.Development.json rename to TodoApiDTO/appsettings.Development.json index 8983e0fc..11b4c79f 100644 --- a/appsettings.Development.json +++ b/TodoApiDTO/appsettings.Development.json @@ -5,5 +5,8 @@ "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } + }, + "ConnectionStrings": { + "TodosDatabase": "Server=DESKTOP-0ROQ806\\SQLEXPRESS;Database=ToDos;Trusted_Connection=True;" } -} +} \ No newline at end of file diff --git a/appsettings.json b/TodoApiDTO/appsettings.json similarity index 100% rename from appsettings.json rename to TodoApiDTO/appsettings.json