diff --git a/fundamentals/minimal-apis/samples/IResultImplementation/ContactsHandler.cs b/fundamentals/minimal-apis/samples/IResultImplementation/ContactsHandler.cs new file mode 100644 index 00000000..7f77c023 --- /dev/null +++ b/fundamentals/minimal-apis/samples/IResultImplementation/ContactsHandler.cs @@ -0,0 +1,100 @@ +using IResultImplementation.Data; +using IResultImplementation.Models; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace IResultImplementation +{ + public static class ContactsHandler + { + + // GET: api/Contacts + public static IResult GetContacts(IResultImplementationContext context) + { + return TypedResults.Ok(context.Contact.ToList()); + } + + // GET: api/Contacts/5 + [HttpGet("{id}")] + public static IResult GetContact(IResultImplementationContext context, int id) + { + var contact = context.Contact.Where(c => c.Id == id).FirstOrDefault(); + + if (contact == null) + { + return TypedResults.NotFound(); + } + + return TypedResults.Ok(contact); + } + + + // POST: api/Contacts + // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 + [HttpPost] + public static IResult PostContact(IResultImplementationContext context, Contact contact) + { + context.Contact.Add(contact); + context.SaveChanges(); + + return TypedResults.CreatedAtRoute(contact, nameof(ContactsHandler.GetContact)); + } + + // PUT: api/Contacts/5 + // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 + [HttpPut("{id}")] + public static IResult PutContact(IResultImplementationContext context, int id, Contact contact) + { + if (id != contact.Id) + { + return TypedResults.BadRequest(); + } + + context.Entry(contact).State = Microsoft.EntityFrameworkCore.EntityState.Modified; + + try + { + context.SaveChanges(); + } + catch (DbUpdateConcurrencyException) + { + if (!ContactExists(context, id)) + { + return TypedResults.NotFound(); + } + else + { + throw; + } + } + + return TypedResults.NoContent(); + } + + + // DELETE: api/Contacts/5 + [HttpDelete("{id}")] + public static IResult DeleteContact(IResultImplementationContext context, int id) + { + if (context.Contact == null) + { + return TypedResults.NotFound(); + } + var contact = context.Contact.Find(id); + if (contact == null) + { + return TypedResults.NotFound(); + } + + context.Contact.Remove(contact); + context.SaveChanges(); + + return TypedResults.NoContent(); + } + + private static bool ContactExists(IResultImplementationContext context, int id) + { + return (context.Contact?.Any(e => e.Id == id)).GetValueOrDefault(); + } + } +} diff --git a/fundamentals/minimal-apis/samples/IResultImplementation/Data/IResultImplementationContext.cs b/fundamentals/minimal-apis/samples/IResultImplementation/Data/IResultImplementationContext.cs new file mode 100644 index 00000000..209d2c37 --- /dev/null +++ b/fundamentals/minimal-apis/samples/IResultImplementation/Data/IResultImplementationContext.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using IResultImplementation.Models; +using Microsoft.EntityFrameworkCore; + +namespace IResultImplementation.Data +{ + public class IResultImplementationContext : DbContext + { + public IResultImplementationContext(DbContextOptions options) + : base(options) + { + } + public IResultImplementationContext() + { + } + + + public virtual DbSet Contact { get; set; } = default!; + } +} diff --git a/fundamentals/minimal-apis/samples/IResultImplementation/IResultImplementation.csproj b/fundamentals/minimal-apis/samples/IResultImplementation/IResultImplementation.csproj new file mode 100644 index 00000000..100f7efb --- /dev/null +++ b/fundamentals/minimal-apis/samples/IResultImplementation/IResultImplementation.csproj @@ -0,0 +1,23 @@ + + + + net7.0 + enable + enable + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/fundamentals/minimal-apis/samples/IResultImplementation/Models/Contact.cs b/fundamentals/minimal-apis/samples/IResultImplementation/Models/Contact.cs new file mode 100644 index 00000000..1b6acc21 --- /dev/null +++ b/fundamentals/minimal-apis/samples/IResultImplementation/Models/Contact.cs @@ -0,0 +1,11 @@ +namespace IResultImplementation.Models +{ + public class Contact + { + public int Id { get; set; } + + public string Name { get; set; } = String.Empty; + public string Email { get; set; } = String.Empty; + public string PhoneNumber { get; set; } = String.Empty; + } +} diff --git a/fundamentals/minimal-apis/samples/IResultImplementation/Program.cs b/fundamentals/minimal-apis/samples/IResultImplementation/Program.cs new file mode 100644 index 00000000..7469655b --- /dev/null +++ b/fundamentals/minimal-apis/samples/IResultImplementation/Program.cs @@ -0,0 +1,23 @@ +using IResultImplementation; +using IResultImplementation.Data; +using Microsoft.EntityFrameworkCore; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddDbContext(options => + options.UseInMemoryDatabase("Contacts")); +// Add services to the container. +builder.Services.AddControllers(); +var app = builder.Build(); + +// Configure the HTTP request pipeline. + +app.UseHttpsRedirection(); +app.MapControllers(); + +app.MapGet("/api/contacts", ContactsHandler.GetContacts); +app.MapGet("/api/contacts/{id}", ContactsHandler.GetContact); +app.MapPost("/api/contacts", ContactsHandler.PostContact); +app.MapPut("/api/contacts/{id}", ContactsHandler.PutContact); +app.MapDelete("/api/contacts/{id}", ContactsHandler.DeleteContact); + +app.Run(); diff --git a/fundamentals/minimal-apis/samples/IResultImplementation/Tests/IResultImplementationTest.cs b/fundamentals/minimal-apis/samples/IResultImplementation/Tests/IResultImplementationTest.cs new file mode 100644 index 00000000..1e293e1f --- /dev/null +++ b/fundamentals/minimal-apis/samples/IResultImplementation/Tests/IResultImplementationTest.cs @@ -0,0 +1,111 @@ +using IResultImplementation.Data; +using IResultImplementation.Models; +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.EntityFrameworkCore; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace IResultImplementation.Tests +{ + [TestClass] + public class IResultImplementationTest + { + public IQueryable? Data { get; set; } + public Mock>? MockSet { get; set; } + [TestInitialize] + public void Setup() + { + Data = new List() + { + new Contact() { Id = 1, Name = "John", Email = "john@tmail.com", PhoneNumber = "1234567890" }, + new Contact() { Id = 2, Name = "Jane", Email = "Jane@kam.com", PhoneNumber = "29384736273" }, + new Contact() {Id = 3, Name = "Kahn", Email = "ema@email.com", PhoneNumber = "23239029202"} + }.AsQueryable(); + + MockSet = new Mock>(); + MockSet.As>().Setup(m => m.Provider).Returns(Data.Provider); + MockSet.As>().Setup(m => m.Expression).Returns(Data.Expression); + MockSet.As>().Setup(m => m.ElementType).Returns(Data.ElementType); + MockSet.As>().Setup(m => m.GetEnumerator()).Returns(() => Data.GetEnumerator()); + } + [TestMethod] + public void GetContactsReturnsContactsFromDatabase() + { + //Arrange + var mockContext = new Mock(); + mockContext.Setup(c => c.Contact).Returns(MockSet!.Object); + int expectedStatusCode = 200; + int expectedItemCount = 3; + + //Act + var result = (Ok>)ContactsHandler.GetContacts(mockContext.Object); + + //Assert + Assert.AreEqual(expectedStatusCode, result.StatusCode); + Assert.AreEqual(expectedItemCount, result.Value?.Count); + + } + + [TestMethod] + public void GetContactReturnsAContactFromDatabase() + { + //Arrange + var mockContext = new Mock(); + mockContext.Setup(c => c.Contact).Returns(MockSet!.Object); + int expectedStatusCode = 200; + int expectedUserId = 2; + + //Act + var result = (Ok)ContactsHandler.GetContact(mockContext.Object, expectedUserId); + + //Assert + Assert.AreEqual(expectedStatusCode, result.StatusCode); + Assert.AreEqual(expectedUserId, result.Value?.Id); + + } + + [TestMethod] + public void GetContactReturnsNotFound() + { + //Arrange + var mockContext = new Mock(); + mockContext.Setup(c => c.Contact).Returns(MockSet!.Object); + int expectedStatusCode = 404; + int expectedUserId = 20; + + //Act + var result = (NotFound)ContactsHandler.GetContact(mockContext.Object, expectedUserId); + + //Assert + Assert.AreEqual(expectedStatusCode, result.StatusCode); + + } + + [TestMethod] + public void CreateTodoSavesContactToDatabase() + { + //Arrange + var mockDbContextOptions = new Mock>(); + var mockContext = new Mock(); + mockContext.Setup(c => c.Contact).Returns(MockSet!.Object); + mockContext.Setup(c => c.Contact.Add(It.IsAny())).Callback(contact => Data = Data.Append(contact)); + var newContact = new Contact() + { + Id = 4, + Name = "John Doe", + Email = "akd@omail.com", + PhoneNumber = "1234567890" + }; + int expectedStatusCode = 201; + int expectedItemCount = 4; + + //Act + var result = (CreatedAtRoute)ContactsHandler.PostContact(mockContext.Object, newContact); + + //Assert + Assert.AreEqual(newContact, result.Value); + Assert.AreEqual(expectedStatusCode, result.StatusCode); + Assert.AreEqual(expectedItemCount, Data.Count()); + } + } +} diff --git a/fundamentals/minimal-apis/samples/IResultImplementation/appsettings.Development.json b/fundamentals/minimal-apis/samples/IResultImplementation/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/fundamentals/minimal-apis/samples/IResultImplementation/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/fundamentals/minimal-apis/samples/IResultImplementation/appsettings.json b/fundamentals/minimal-apis/samples/IResultImplementation/appsettings.json new file mode 100644 index 00000000..10f68b8c --- /dev/null +++ b/fundamentals/minimal-apis/samples/IResultImplementation/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +}