diff --git a/Models/TodoItem.cs b/Models/TodoItem.cs
deleted file mode 100644
index 1f6e5465..00000000
--- a/Models/TodoItem.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace TodoApi.Models
-{
- #region snippet
- public class TodoItem
- {
- public long Id { get; set; }
- public string Name { get; set; }
- public bool IsComplete { get; set; }
- public string Secret { get; set; }
- }
- #endregion
-}
\ No newline at end of file
diff --git a/README.md b/README.md
deleted file mode 100644
index 466e41fd..00000000
--- a/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# TodoService
\ 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.sln b/TodoApiDTO.sln
index e49c182b..931e90c2 100644
--- a/TodoApiDTO.sln
+++ b/TodoApiDTO.sln
@@ -1,9 +1,11 @@

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.33815.320
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoApiDTO", "TodoApiDTO.csproj", "{623124F9-F5BA-42DD-BC26-A1720774229C}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TodoApiDTOTests", "TodoApiDTOTests\TodoApiDTOTests.csproj", "{B16AF459-6CB0-4F47-9040-2BBF1D7E857B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoApiDTO", "TodoApiDTO\TodoApiDTO.csproj", "{AB010941-7483-4C99-BE32-505E505A154D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -11,10 +13,14 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {623124F9-F5BA-42DD-BC26-A1720774229C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {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
+ {B16AF459-6CB0-4F47-9040-2BBF1D7E857B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B16AF459-6CB0-4F47-9040-2BBF1D7E857B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B16AF459-6CB0-4F47-9040-2BBF1D7E857B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B16AF459-6CB0-4F47-9040-2BBF1D7E857B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AB010941-7483-4C99-BE32-505E505A154D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AB010941-7483-4C99-BE32-505E505A154D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AB010941-7483-4C99-BE32-505E505A154D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AB010941-7483-4C99-BE32-505E505A154D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/TodoApiDTO/Controllers/TodoItemsController.cs b/TodoApiDTO/Controllers/TodoItemsController.cs
new file mode 100644
index 00000000..88d6352e
--- /dev/null
+++ b/TodoApiDTO/Controllers/TodoItemsController.cs
@@ -0,0 +1,118 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using TodoApi.Models;
+using TodoApiDTO.Services;
+
+namespace TodoApi.Controllers
+{
+ [Route("api/[controller]")]
+ [Produces("application/json")]
+ [ApiController]
+ public class TodoItemsController : ControllerBase
+ {
+ private readonly ITodoService _service;
+
+ public TodoItemsController(ITodoService service)
+ {
+ _service = service;
+ }
+
+ ///
+ /// Gets ToDoItems.
+ ///
+ ///
+ [HttpGet]
+ [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List))]
+ public async Task GetTodoItems()
+ {
+ return Ok(await _service.Get());
+ }
+
+ ///
+ /// Gets a specific ToDoItem.
+ ///
+ /// Item ID
+ ///
+ [HttpGet("{id}")]
+ [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(TodoItemDTO))]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task GetTodoItem(long id)
+ {
+ var todoItem = await _service.Get(id);
+
+ if (todoItem is null)
+ {
+ return NotFound();
+ }
+
+ return Ok(todoItem);
+ }
+
+ ///
+ /// Updates a specific ToDoItem.
+ ///
+ /// Item ID
+ /// Modified item
+ ///
+ [HttpPut("{id}")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ public async Task UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
+ {
+ if (id != todoItemDTO.Id)
+ {
+ return BadRequest();
+ }
+
+ var wasUpdated = await _service.Update(id, todoItemDTO);
+
+ if (!wasUpdated)
+ {
+ return NotFound();
+ }
+
+ return NoContent();
+ }
+
+ ///
+ /// Creates a new ToDoItem.
+ ///
+ /// New item
+ ///
+ [HttpPost]
+ [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(TodoItemDTO))]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task CreateTodoItem(TodoItemDTO todoItemDTO)
+ {
+ var todoItem = await _service.Create(todoItemDTO);
+
+ return CreatedAtAction(
+ nameof(GetTodoItem),
+ new { id = todoItem.Id },
+ todoItem);
+ }
+
+ ///
+ /// Deletes a spefific ToDoItem.
+ ///
+ /// Item ID
+ ///
+ [HttpDelete("{id}")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task DeleteTodoItem(long id)
+ {
+ var wasDeleted = await _service.Delete(id);
+
+ if (!wasDeleted)
+ {
+ return NotFound();
+ }
+
+ return NoContent();
+ }
+ }
+}
diff --git a/Models/TodoContext.cs b/TodoApiDTO/Data/TodoContext.cs
similarity index 63%
rename from Models/TodoContext.cs
rename to TodoApiDTO/Data/TodoContext.cs
index 6e59e363..fb376a91 100644
--- a/Models/TodoContext.cs
+++ b/TodoApiDTO/Data/TodoContext.cs
@@ -1,14 +1,17 @@
using Microsoft.EntityFrameworkCore;
-namespace TodoApi.Models
+namespace TodoApiDTO.Data
{
public class TodoContext : DbContext
{
+ public TodoContext() { }
+
+
public TodoContext(DbContextOptions options)
: base(options)
{
}
- public DbSet TodoItems { get; set; }
+ public virtual DbSet TodoItems { get; set; }
}
}
\ No newline at end of file
diff --git a/TodoApiDTO/Data/TodoItem.cs b/TodoApiDTO/Data/TodoItem.cs
new file mode 100644
index 00000000..da684609
--- /dev/null
+++ b/TodoApiDTO/Data/TodoItem.cs
@@ -0,0 +1,14 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace TodoApiDTO.Data
+{
+ #region snippet
+ public class TodoItem
+ {
+ public long Id { get; set; }
+ public string? Name { get; set; }
+ public bool IsComplete { get; set; }
+ public string? Secret { get; set; }
+ }
+ #endregion
+}
\ No newline at end of file
diff --git a/TodoApiDTO/Migrations/20230621182622_InitialCreate.Designer.cs b/TodoApiDTO/Migrations/20230621182622_InitialCreate.Designer.cs
new file mode 100644
index 00000000..0478f458
--- /dev/null
+++ b/TodoApiDTO/Migrations/20230621182622_InitialCreate.Designer.cs
@@ -0,0 +1,51 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using TodoApiDTO.Data;
+
+#nullable disable
+
+namespace TodoApiDTO.Migrations
+{
+ [DbContext(typeof(TodoContext))]
+ [Migration("20230621182622_InitialCreate")]
+ partial class InitialCreate
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.7")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("TodoApi.Models.TodoItem", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("IsComplete")
+ .HasColumnType("bit");
+
+ b.Property("Name")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Secret")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.ToTable("TodoItems");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/TodoApiDTO/Migrations/20230621182622_InitialCreate.cs b/TodoApiDTO/Migrations/20230621182622_InitialCreate.cs
new file mode 100644
index 00000000..7d1c20ca
--- /dev/null
+++ b/TodoApiDTO/Migrations/20230621182622_InitialCreate.cs
@@ -0,0 +1,36 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace TodoApiDTO.Migrations
+{
+ ///
+ public partial class InitialCreate : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "TodoItems",
+ columns: table => new
+ {
+ Id = table.Column(type: "bigint", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ Name = table.Column(type: "nvarchar(max)", nullable: true),
+ IsComplete = table.Column(type: "bit", nullable: false),
+ Secret = table.Column(type: "nvarchar(max)", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_TodoItems", x => x.Id);
+ });
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "TodoItems");
+ }
+ }
+}
diff --git a/TodoApiDTO/Migrations/TodoContextModelSnapshot.cs b/TodoApiDTO/Migrations/TodoContextModelSnapshot.cs
new file mode 100644
index 00000000..bd70a378
--- /dev/null
+++ b/TodoApiDTO/Migrations/TodoContextModelSnapshot.cs
@@ -0,0 +1,48 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using TodoApiDTO.Data;
+
+#nullable disable
+
+namespace TodoApiDTO.Migrations
+{
+ [DbContext(typeof(TodoContext))]
+ partial class TodoContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.7")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("TodoApi.Models.TodoItem", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("IsComplete")
+ .HasColumnType("bit");
+
+ b.Property("Name")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Secret")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.ToTable("TodoItems");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Models/TodoItemDTO.cs b/TodoApiDTO/Models/TodoItemDTO.cs
similarity index 81%
rename from Models/TodoItemDTO.cs
rename to TodoApiDTO/Models/TodoItemDTO.cs
index e66a500a..eb928cf7 100644
--- a/Models/TodoItemDTO.cs
+++ b/TodoApiDTO/Models/TodoItemDTO.cs
@@ -4,7 +4,7 @@
public class TodoItemDTO
{
public long Id { get; set; }
- public string Name { get; set; }
+ public string? Name { get; set; }
public bool IsComplete { get; set; }
}
#endregion
diff --git a/Program.cs b/TodoApiDTO/Program.cs
similarity index 100%
rename from Program.cs
rename to TodoApiDTO/Program.cs
diff --git a/Properties/launchSettings.json b/TodoApiDTO/Properties/launchSettings.json
similarity index 95%
rename from Properties/launchSettings.json
rename to TodoApiDTO/Properties/launchSettings.json
index 6766196a..b9bf0083 100644
--- a/Properties/launchSettings.json
+++ b/TodoApiDTO/Properties/launchSettings.json
@@ -1,12 +1,4 @@
{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:56416/",
- "sslPort": 44331
- }
- },
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
@@ -17,11 +9,18 @@
},
"TodoApiDTO": {
"commandName": "Project",
- "launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
+ },
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:56416/",
+ "sslPort": 44331
+ }
}
}
\ No newline at end of file
diff --git a/TodoApiDTO/README.md b/TodoApiDTO/README.md
new file mode 100644
index 00000000..551b2102
--- /dev/null
+++ b/TodoApiDTO/README.md
@@ -0,0 +1,6 @@
+# TodoService
+
+1. Äîáàâèòü ñâàããåð
+2. Õðàíèòü ñïèñîê çàäà÷ â SQL Server (ñåé÷àñ èñïîëüçóåòñÿ InMemoryDB). Ñòðîêà ñîåäèíåíèÿ äîëæíà õðàíèòüñÿ â ôàéëå appsettings.
+3. Ñäåëàòü ðåôàêòîðèíã - âûäåëèòü ñëîè Data Access Layer, Business Layer
+4. Íàïèñàòü þíèò-òåñòû íà áèçíåñ îïåðàöèè
diff --git a/TodoApiDTO/Services/ITodoService.cs b/TodoApiDTO/Services/ITodoService.cs
new file mode 100644
index 00000000..22e8baf3
--- /dev/null
+++ b/TodoApiDTO/Services/ITodoService.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using TodoApi.Models;
+
+namespace TodoApiDTO.Services
+{
+ public interface ITodoService
+ {
+ Task Create(TodoItemDTO todoItemDTO);
+ Task Delete(long id);
+ Task> Get();
+ Task Get(long id);
+ Task Update(long id, TodoItemDTO todoItemDTO);
+ }
+}
\ No newline at end of file
diff --git a/Controllers/TodoItemsController.cs b/TodoApiDTO/Services/TodoService.cs
similarity index 53%
rename from Controllers/TodoItemsController.cs
rename to TodoApiDTO/Services/TodoService.cs
index 0ef138e7..be1c5d00 100644
--- a/Controllers/TodoItemsController.cs
+++ b/TodoApiDTO/Services/TodoService.cs
@@ -1,56 +1,75 @@
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TodoApi.Models;
+using TodoApiDTO.Data;
-namespace TodoApi.Controllers
+namespace TodoApiDTO.Services
{
- [Route("api/[controller]")]
- [ApiController]
- public class TodoItemsController : ControllerBase
+ public class TodoService : ITodoService
{
private readonly TodoContext _context;
- public TodoItemsController(TodoContext context)
+ public TodoService(TodoContext context)
{
_context = context;
}
- [HttpGet]
- public async Task>> GetTodoItems()
+ public async Task Create(TodoItemDTO todoItemDTO)
+ {
+ var todoItem = new TodoItem
+ {
+ IsComplete = todoItemDTO.IsComplete,
+ Name = todoItemDTO.Name
+ };
+
+ _context.TodoItems.Add(todoItem);
+ await _context.SaveChangesAsync();
+
+ return ItemToDTO(todoItem);
+ }
+
+ public async Task Delete(long id)
+ {
+ var todoItem = await _context.TodoItems.FindAsync(id);
+
+ if (todoItem is null)
+ {
+ return false;
+ }
+
+ _context.TodoItems.Remove(todoItem);
+ await _context.SaveChangesAsync();
+
+ return true;
+ }
+
+ public async Task> Get()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
- [HttpGet("{id}")]
- public async Task> GetTodoItem(long id)
+ public async Task Get(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
- if (todoItem == null)
+ if (todoItem is null)
{
- return NotFound();
+ return default;
}
return ItemToDTO(todoItem);
}
- [HttpPut("{id}")]
- public async Task UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
+ public async Task Update(long id, TodoItemDTO todoItemDTO)
{
- if (id != todoItemDTO.Id)
- {
- return BadRequest();
- }
-
var todoItem = await _context.TodoItems.FindAsync(id);
- if (todoItem == null)
+ if (todoItem is null)
{
- return NotFound();
+ return false;
}
todoItem.Name = todoItemDTO.Name;
@@ -62,55 +81,21 @@ public async Task UpdateTodoItem(long id, TodoItemDTO todoItemDTO
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
- return NotFound();
+ return false;
}
- 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();
+ return true;
}
private bool TodoItemExists(long id) =>
- _context.TodoItems.Any(e => e.Id == id);
+ _context.TodoItems.Any(e => e.Id == id);
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
- new TodoItemDTO
+ new()
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
- };
+ };
}
-}
+}
\ No newline at end of file
diff --git a/Startup.cs b/TodoApiDTO/Startup.cs
similarity index 71%
rename from Startup.cs
rename to TodoApiDTO/Startup.cs
index bbfbc83d..2fa66a88 100644
--- a/Startup.cs
+++ b/TodoApiDTO/Startup.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
+using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@@ -11,7 +13,8 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
-using TodoApi.Models;
+using TodoApiDTO.Data;
+using TodoApiDTO.Services;
namespace TodoApi
{
@@ -28,8 +31,17 @@ public Startup(IConfiguration configuration)
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext(opt =>
- opt.UseInMemoryDatabase("TodoList"));
+ opt.UseSqlServer(Configuration.GetConnectionString("VelvetechDatabase")));
+
+ services.AddTransient();
+
services.AddControllers();
+
+ services.AddSwaggerGen(options =>
+ {
+ var xmlFileName = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
+ options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFileName));
+ });
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -40,6 +52,9 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseDeveloperExceptionPage();
}
+ app.UseSwagger();
+ app.UseSwaggerUI();
+
app.UseHttpsRedirection();
app.UseRouting();
diff --git a/TodoApiDTO/TodoApiDTO.csproj b/TodoApiDTO/TodoApiDTO.csproj
new file mode 100644
index 00000000..4d0eabfd
--- /dev/null
+++ b/TodoApiDTO/TodoApiDTO.csproj
@@ -0,0 +1,33 @@
+
+
+
+ net7.0
+ enable
+ True
+
+
+
+ 1701;1702;CS1591;
+
+
+
+ 1701;1702;CS1591;
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
diff --git a/appsettings.Development.json b/TodoApiDTO/appsettings.Development.json
similarity index 100%
rename from appsettings.Development.json
rename to TodoApiDTO/appsettings.Development.json
diff --git a/appsettings.json b/TodoApiDTO/appsettings.json
similarity index 52%
rename from appsettings.json
rename to TodoApiDTO/appsettings.json
index d9d9a9bf..222d0e99 100644
--- a/appsettings.json
+++ b/TodoApiDTO/appsettings.json
@@ -1,4 +1,7 @@
{
+ "ConnectionStrings": {
+ "VelvetechDatabase": "Server=localhost; Database=default; User Id=sa; Password=DiwhAWmXFZ@b3jXA8T.A; TrustServerCertificate=True"
+ },
"Logging": {
"LogLevel": {
"Default": "Information",
diff --git a/TodoApiDTOTests/TodoApiDTOTests.csproj b/TodoApiDTOTests/TodoApiDTOTests.csproj
new file mode 100644
index 00000000..c2b9ed2f
--- /dev/null
+++ b/TodoApiDTOTests/TodoApiDTOTests.csproj
@@ -0,0 +1,32 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+ false
+ true
+ Library
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/TodoApiDTOTests/TodoServiceTests.cs b/TodoApiDTOTests/TodoServiceTests.cs
new file mode 100644
index 00000000..81994f35
--- /dev/null
+++ b/TodoApiDTOTests/TodoServiceTests.cs
@@ -0,0 +1,167 @@
+using Microsoft.EntityFrameworkCore;
+using Moq;
+using Moq.EntityFrameworkCore;
+using TodoApi.Models;
+using TodoApiDTO.Data;
+using TodoApiDTO.Services;
+using Xunit;
+
+namespace TodoApiDTOTests
+{
+ public class TodoServiceTests :IDisposable
+ {
+ private readonly Mock _context;
+
+ private static readonly List _todos = new()
+ {
+ new()
+ {
+ Id = 202
+ },
+ new()
+ {
+ Id = 302
+ },
+ new()
+ {
+ Id = 402
+ }
+ };
+
+ public TodoServiceTests()
+ {
+ var contextMock = new Mock();
+ contextMock.Setup(x => x.TodoItems).ReturnsDbSet(_todos);
+ contextMock.Setup(x => x.TodoItems.FindAsync(It.IsAny