From 09b7db8aaf4be04662945dba893fa839a5c4d046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20G=C3=B3reczny?= Date: Thu, 10 Dec 2020 13:15:11 +0100 Subject: [PATCH 1/8] Added Either return type --- .../SessionCompanion.ApiReturn/Either.cs | 65 +++++++++++++++++++ .../SessionCompanion.ApiExtensions.csproj | 7 ++ SessionCompanion/SessionCompanion.sln | 11 +++- .../Controllers/CharacterController.cs | 8 +-- .../SessionCompanion/SessionCompanion.csproj | 1 + SessionCompanion/SessionCompanion/Startup.cs | 2 +- 6 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 SessionCompanion/SessionCompanion.ApiReturn/Either.cs create mode 100644 SessionCompanion/SessionCompanion.ApiReturn/SessionCompanion.ApiExtensions.csproj diff --git a/SessionCompanion/SessionCompanion.ApiReturn/Either.cs b/SessionCompanion/SessionCompanion.ApiReturn/Either.cs new file mode 100644 index 0000000..5f279a0 --- /dev/null +++ b/SessionCompanion/SessionCompanion.ApiReturn/Either.cs @@ -0,0 +1,65 @@ +namespace SessionCompanion.ApiReturn +{ + using System; + + public class Either + { + private readonly TL left; + + private readonly TR right; + + private readonly bool isLeft; + + public Either(TL left) + { + this.left = left; + this.isLeft = true; + } + + public Either(TR right) + { + this.right = right; + this.isLeft = false; + } + + public T Match(Func leftFunc, Func rightFunc) + { + if (leftFunc == null) + { + throw new ArgumentNullException(nameof(leftFunc)); + } + + if (rightFunc == null) + { + throw new ArgumentNullException(nameof(rightFunc)); + } + + return this.isLeft ? leftFunc(this.left) : rightFunc(this.right); + } + + /// + /// If right value is assigned, execute an action on it. + /// + /// Akcja do wykonania + public void DoRight(Action rightAction) + { + if (rightAction == null) + { + throw new ArgumentNullException(nameof(rightAction)); + } + + if (!this.isLeft) + { + rightAction(this.right); + } + } + + public TL LeftOrDefault() => this.Match(l => l, r => default(TL)); + + public TR RightOrDefault() => this.Match(l => default(TR), r => r); + + public static implicit operator Either(TL left) => new Either(left); + + public static implicit operator Either(TR right) => new Either(right); + } +} diff --git a/SessionCompanion/SessionCompanion.ApiReturn/SessionCompanion.ApiExtensions.csproj b/SessionCompanion/SessionCompanion.ApiReturn/SessionCompanion.ApiExtensions.csproj new file mode 100644 index 0000000..f208d30 --- /dev/null +++ b/SessionCompanion/SessionCompanion.ApiReturn/SessionCompanion.ApiExtensions.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/SessionCompanion/SessionCompanion.sln b/SessionCompanion/SessionCompanion.sln index c634e22..c12041e 100644 --- a/SessionCompanion/SessionCompanion.sln +++ b/SessionCompanion/SessionCompanion.sln @@ -4,12 +4,17 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 16.0.30717.126 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SessionCompanion", "SessionCompanion\SessionCompanion.csproj", "{C646135F-16CE-4B16-B041-252D343D4E01}" + ProjectSection(ProjectDependencies) = postProject + {0CBA48BB-7C1F-42FB-9008-C75A7681ED09} = {0CBA48BB-7C1F-42FB-9008-C75A7681ED09} + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SessionCompanion.Database", "SessionCompanion.Database\SessionCompanion.Database.csproj", "{CA05189B-A4AB-4946-80DC-EFA075A10F09}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SessionCompanion.ViewModels", "SessionCompanion.ViewModels\SessionCompanion.ViewModels.csproj", "{7762AA75-7B60-4F28-B80A-B03E39140F89}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SessionCompanion.Services", "SessionCompanion.Services\SessionCompanion.Services.csproj", "{C0A172ED-0F4C-4E78-8B64-28E2A756F62F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SessionCompanion.Services", "SessionCompanion.Services\SessionCompanion.Services.csproj", "{C0A172ED-0F4C-4E78-8B64-28E2A756F62F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SessionCompanion.ApiExtensions", "SessionCompanion.ApiReturn\SessionCompanion.ApiExtensions.csproj", "{0CBA48BB-7C1F-42FB-9008-C75A7681ED09}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -33,6 +38,10 @@ Global {C0A172ED-0F4C-4E78-8B64-28E2A756F62F}.Debug|Any CPU.Build.0 = Debug|Any CPU {C0A172ED-0F4C-4E78-8B64-28E2A756F62F}.Release|Any CPU.ActiveCfg = Release|Any CPU {C0A172ED-0F4C-4E78-8B64-28E2A756F62F}.Release|Any CPU.Build.0 = Release|Any CPU + {0CBA48BB-7C1F-42FB-9008-C75A7681ED09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0CBA48BB-7C1F-42FB-9008-C75A7681ED09}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0CBA48BB-7C1F-42FB-9008-C75A7681ED09}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0CBA48BB-7C1F-42FB-9008-C75A7681ED09}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs b/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs index afb6af1..061f08d 100644 --- a/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs +++ b/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs @@ -1,13 +1,11 @@ using System.Threading.Tasks; - using Microsoft.AspNetCore.Mvc; - using SessionCompanion.Services.Interfaces; +using SessionCompanion.ViewModels.CharacterViewModels; +using SessionCompanion.ApiReturn; namespace SessionCompanion.Controllers { - using SessionCompanion.ViewModels.CharacterViewModels; - [Route("api/character")] [ApiController] public class CharacterController : Controller @@ -25,7 +23,7 @@ namespace SessionCompanion.Controllers /// Identyfikator postaci /// ViewModel Postaci [HttpGet("{id}")] - public async Task Get(int id) + public async Task> Get(int id) { return await _service.Get(id); } diff --git a/SessionCompanion/SessionCompanion/SessionCompanion.csproj b/SessionCompanion/SessionCompanion/SessionCompanion.csproj index 576f08d..d020f60 100644 --- a/SessionCompanion/SessionCompanion/SessionCompanion.csproj +++ b/SessionCompanion/SessionCompanion/SessionCompanion.csproj @@ -41,6 +41,7 @@ + diff --git a/SessionCompanion/SessionCompanion/Startup.cs b/SessionCompanion/SessionCompanion/Startup.cs index 7cb2723..c3c0cef 100644 --- a/SessionCompanion/SessionCompanion/Startup.cs +++ b/SessionCompanion/SessionCompanion/Startup.cs @@ -45,7 +45,7 @@ namespace SessionCompanion services.AddSwaggerGen(s => { - s.SwaggerDoc("v1", new OpenApiInfo { Title = "Dostêpne API", Version = "v1" }); + s.SwaggerDoc("v1", new OpenApiInfo { Title = "Dost�pne API", Version = "v1" }); var basePath = AppContext.BaseDirectory; var xmlPath = Path.Combine(basePath, "SessionCompanion.xml"); s.IncludeXmlComments(xmlPath); From 2cac5bd8297b48a328db356dc600897d65828371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20G=C3=B3reczny?= Date: Thu, 10 Dec 2020 13:55:31 +0100 Subject: [PATCH 2/8] Fix mapper --- SessionCompanion/SessionCompanion/Startup.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SessionCompanion/SessionCompanion/Startup.cs b/SessionCompanion/SessionCompanion/Startup.cs index c3c0cef..5318f64 100644 --- a/SessionCompanion/SessionCompanion/Startup.cs +++ b/SessionCompanion/SessionCompanion/Startup.cs @@ -40,7 +40,9 @@ namespace SessionCompanion Configuration.GetConnectionString("DefaultConnection"))); services.AddRepositories(); services.AddServices(); - services.AddAutoMapper(typeof(Startup)); + + services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + services.AddSignalR(); services.AddSwaggerGen(s => From bc6709e9050453f923aa1de2208604d8f2119aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20G=C3=B3reczny?= Date: Thu, 10 Dec 2020 14:31:40 +0100 Subject: [PATCH 3/8] Small fix --- .../SessionCompanion.ApiReturn/Either.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/SessionCompanion/SessionCompanion.ApiReturn/Either.cs b/SessionCompanion/SessionCompanion.ApiReturn/Either.cs index 5f279a0..f569090 100644 --- a/SessionCompanion/SessionCompanion.ApiReturn/Either.cs +++ b/SessionCompanion/SessionCompanion.ApiReturn/Either.cs @@ -22,6 +22,14 @@ this.isLeft = false; } + /// + /// Bazowa metoda dopasowania wzorów. + /// JeÅ›li podana jest wartość lewa, to Match zwróci wynik lewej funkcji, w przeciwnym razie wynik prawej funkcji. + /// + /// + /// Lewa funkcja + /// Prawa funkcja + /// Wynik prawej/lewej funkcji public T Match(Func leftFunc, Func rightFunc) { if (leftFunc == null) @@ -37,10 +45,6 @@ return this.isLeft ? leftFunc(this.left) : rightFunc(this.right); } - /// - /// If right value is assigned, execute an action on it. - /// - /// Akcja do wykonania public void DoRight(Action rightAction) { if (rightAction == null) From 6131bbe706ecb8a6bdc95d54355ee7bcb43787c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20G=C3=B3reczny?= Date: Thu, 10 Dec 2020 15:08:05 +0100 Subject: [PATCH 4/8] New Type moved to different project and changed on of the profiles --- .../EitherType}/Either.cs | 6 +++--- .../SessionCompanion.Extensions.csproj} | 0 .../SessionCompanion.Services/Profiles/UserProfile.cs | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) rename SessionCompanion/{SessionCompanion.ApiReturn => SessionCompanion.Extensions/EitherType}/Either.cs (96%) rename SessionCompanion/{SessionCompanion.ApiReturn/SessionCompanion.ApiExtensions.csproj => SessionCompanion.Extensions/SessionCompanion.Extensions.csproj} (100%) diff --git a/SessionCompanion/SessionCompanion.ApiReturn/Either.cs b/SessionCompanion/SessionCompanion.Extensions/EitherType/Either.cs similarity index 96% rename from SessionCompanion/SessionCompanion.ApiReturn/Either.cs rename to SessionCompanion/SessionCompanion.Extensions/EitherType/Either.cs index f569090..ae83888 100644 --- a/SessionCompanion/SessionCompanion.ApiReturn/Either.cs +++ b/SessionCompanion/SessionCompanion.Extensions/EitherType/Either.cs @@ -1,7 +1,7 @@ -namespace SessionCompanion.ApiReturn -{ - using System; +using System; +namespace SessionCompanion.Extensions.EitherType +{ public class Either { private readonly TL left; diff --git a/SessionCompanion/SessionCompanion.ApiReturn/SessionCompanion.ApiExtensions.csproj b/SessionCompanion/SessionCompanion.Extensions/SessionCompanion.Extensions.csproj similarity index 100% rename from SessionCompanion/SessionCompanion.ApiReturn/SessionCompanion.ApiExtensions.csproj rename to SessionCompanion/SessionCompanion.Extensions/SessionCompanion.Extensions.csproj diff --git a/SessionCompanion/SessionCompanion.Services/Profiles/UserProfile.cs b/SessionCompanion/SessionCompanion.Services/Profiles/UserProfile.cs index 5b2c1a1..4c7fdc2 100644 --- a/SessionCompanion/SessionCompanion.Services/Profiles/UserProfile.cs +++ b/SessionCompanion/SessionCompanion.Services/Profiles/UserProfile.cs @@ -11,8 +11,7 @@ namespace SessionCompanion.Services.Profiles { public UserProfile() { - CreateMap(); - CreateMap(); + CreateMap().ReverseMap(); } } } From 9efefd96fe9a5c89222914fff5bafcc57f8c8108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20G=C3=B3reczny?= Date: Thu, 10 Dec 2020 15:28:00 +0100 Subject: [PATCH 5/8] SES-91 Added error middleware --- .../ApiErrors/ErrorDetails.cs | 26 +++++++++++ .../SessionCompanion.Extensions.csproj | 4 ++ SessionCompanion/SessionCompanion.sln | 13 +++--- .../Configurations/ExceptionMiddleware.cs | 43 +++++++++++++++++++ .../ExceptionMiddlewareExtensions.cs | 19 ++++++++ .../SessionCompanion/SessionCompanion.csproj | 2 +- SessionCompanion/SessionCompanion/Startup.cs | 4 ++ 7 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 SessionCompanion/SessionCompanion.Extensions/ApiErrors/ErrorDetails.cs create mode 100644 SessionCompanion/SessionCompanion/Configurations/ExceptionMiddleware.cs create mode 100644 SessionCompanion/SessionCompanion/Configurations/ExceptionMiddlewareExtensions.cs diff --git a/SessionCompanion/SessionCompanion.Extensions/ApiErrors/ErrorDetails.cs b/SessionCompanion/SessionCompanion.Extensions/ApiErrors/ErrorDetails.cs new file mode 100644 index 0000000..e6ad261 --- /dev/null +++ b/SessionCompanion/SessionCompanion.Extensions/ApiErrors/ErrorDetails.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Threading.Tasks; + +namespace SessionCompanion.Extensions.ApiErrors +{ + public class ErrorDetails + { + /// + /// Kod bÅ‚Ä™du + /// + public int StatusCode { get; set; } + + /// + /// Wiadomość bÅ‚Ä™du do pokazania + /// + public string Message { get; set; } + + public override string ToString() + { + return JsonSerializer.Serialize(this); + } + } +} diff --git a/SessionCompanion/SessionCompanion.Extensions/SessionCompanion.Extensions.csproj b/SessionCompanion/SessionCompanion.Extensions/SessionCompanion.Extensions.csproj index f208d30..6015009 100644 --- a/SessionCompanion/SessionCompanion.Extensions/SessionCompanion.Extensions.csproj +++ b/SessionCompanion/SessionCompanion.Extensions/SessionCompanion.Extensions.csproj @@ -4,4 +4,8 @@ net5.0 + + + + diff --git a/SessionCompanion/SessionCompanion.sln b/SessionCompanion/SessionCompanion.sln index c12041e..edd8402 100644 --- a/SessionCompanion/SessionCompanion.sln +++ b/SessionCompanion/SessionCompanion.sln @@ -4,9 +4,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 16.0.30717.126 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SessionCompanion", "SessionCompanion\SessionCompanion.csproj", "{C646135F-16CE-4B16-B041-252D343D4E01}" - ProjectSection(ProjectDependencies) = postProject - {0CBA48BB-7C1F-42FB-9008-C75A7681ED09} = {0CBA48BB-7C1F-42FB-9008-C75A7681ED09} - EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SessionCompanion.Database", "SessionCompanion.Database\SessionCompanion.Database.csproj", "{CA05189B-A4AB-4946-80DC-EFA075A10F09}" EndProject @@ -14,7 +11,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SessionCompanion.ViewModels EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SessionCompanion.Services", "SessionCompanion.Services\SessionCompanion.Services.csproj", "{C0A172ED-0F4C-4E78-8B64-28E2A756F62F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SessionCompanion.ApiExtensions", "SessionCompanion.ApiReturn\SessionCompanion.ApiExtensions.csproj", "{0CBA48BB-7C1F-42FB-9008-C75A7681ED09}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SessionCompanion.Extensions", "SessionCompanion.Extensions\SessionCompanion.Extensions.csproj", "{1EE35EB3-C703-407C-B390-5605A0A46884}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -38,10 +35,10 @@ Global {C0A172ED-0F4C-4E78-8B64-28E2A756F62F}.Debug|Any CPU.Build.0 = Debug|Any CPU {C0A172ED-0F4C-4E78-8B64-28E2A756F62F}.Release|Any CPU.ActiveCfg = Release|Any CPU {C0A172ED-0F4C-4E78-8B64-28E2A756F62F}.Release|Any CPU.Build.0 = Release|Any CPU - {0CBA48BB-7C1F-42FB-9008-C75A7681ED09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0CBA48BB-7C1F-42FB-9008-C75A7681ED09}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0CBA48BB-7C1F-42FB-9008-C75A7681ED09}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0CBA48BB-7C1F-42FB-9008-C75A7681ED09}.Release|Any CPU.Build.0 = Release|Any CPU + {1EE35EB3-C703-407C-B390-5605A0A46884}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1EE35EB3-C703-407C-B390-5605A0A46884}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EE35EB3-C703-407C-B390-5605A0A46884}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1EE35EB3-C703-407C-B390-5605A0A46884}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SessionCompanion/SessionCompanion/Configurations/ExceptionMiddleware.cs b/SessionCompanion/SessionCompanion/Configurations/ExceptionMiddleware.cs new file mode 100644 index 0000000..a9ba919 --- /dev/null +++ b/SessionCompanion/SessionCompanion/Configurations/ExceptionMiddleware.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace SessionCompanion.Configurations +{ + using System.Net; + + using Microsoft.AspNetCore.Http; + + using SessionCompanion.Extensions.ApiErrors; + + public class ExceptionMiddleware + { + private readonly RequestDelegate _next; + public ExceptionMiddleware(RequestDelegate next) + { + _next = next; + } + public async Task InvokeAsync(HttpContext httpContext) + { + try + { + await _next(httpContext); + } + catch (Exception ex) + { + await HandleExceptionAsync(httpContext, ex); + } + } + private Task HandleExceptionAsync(HttpContext context, Exception exception) + { + context.Response.ContentType = "application/json"; + context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; + return context.Response.WriteAsync(new ErrorDetails() + { + StatusCode = context.Response.StatusCode, + Message = exception.Message + }.ToString()); + } + } +} diff --git a/SessionCompanion/SessionCompanion/Configurations/ExceptionMiddlewareExtensions.cs b/SessionCompanion/SessionCompanion/Configurations/ExceptionMiddlewareExtensions.cs new file mode 100644 index 0000000..6c3aee6 --- /dev/null +++ b/SessionCompanion/SessionCompanion/Configurations/ExceptionMiddlewareExtensions.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Http; +using System.Net; + +namespace SessionCompanion.Extensions.ApiErrors +{ + using Microsoft.AspNetCore.Diagnostics; + + using SessionCompanion.Configurations; + + public static class ExceptionMiddlewareExtensions + { + public static void ConfigureCustomExceptionMiddleware(this IApplicationBuilder app) + { + app.UseMiddleware(); + } + } +} diff --git a/SessionCompanion/SessionCompanion/SessionCompanion.csproj b/SessionCompanion/SessionCompanion/SessionCompanion.csproj index d020f60..c455a8f 100644 --- a/SessionCompanion/SessionCompanion/SessionCompanion.csproj +++ b/SessionCompanion/SessionCompanion/SessionCompanion.csproj @@ -41,8 +41,8 @@ - + diff --git a/SessionCompanion/SessionCompanion/Startup.cs b/SessionCompanion/SessionCompanion/Startup.cs index 5318f64..6e96eed 100644 --- a/SessionCompanion/SessionCompanion/Startup.cs +++ b/SessionCompanion/SessionCompanion/Startup.cs @@ -21,6 +21,8 @@ namespace SessionCompanion using Microsoft.OpenApi.Models; + using SessionCompanion.Extensions.ApiErrors; + public class Startup { @@ -83,6 +85,8 @@ namespace SessionCompanion app.UseHsts(); } + app.ConfigureCustomExceptionMiddleware(); + app.UseHttpsRedirection(); app.UseStaticFiles(); if (!env.IsDevelopment()) From 8e59538db80c94d0429d9a97bb220e093504c0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20G=C3=B3reczny?= Date: Thu, 10 Dec 2020 17:34:30 +0100 Subject: [PATCH 6/8] Utworzenie modeli success i error --- .../ApiResponses/ErrorResponse.cs | 22 +++++++++++++++ .../ApiResponses/SuccessResponse.cs | 28 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 SessionCompanion/SessionCompanion.ViewModels/ApiResponses/ErrorResponse.cs create mode 100644 SessionCompanion/SessionCompanion.ViewModels/ApiResponses/SuccessResponse.cs diff --git a/SessionCompanion/SessionCompanion.ViewModels/ApiResponses/ErrorResponse.cs b/SessionCompanion/SessionCompanion.ViewModels/ApiResponses/ErrorResponse.cs new file mode 100644 index 0000000..262dd62 --- /dev/null +++ b/SessionCompanion/SessionCompanion.ViewModels/ApiResponses/ErrorResponse.cs @@ -0,0 +1,22 @@ +using System.Text.Json; + +namespace SessionCompanion.ViewModels.ApiResponses +{ + public class ErrorResponse + { + /// + /// Kod bÅ‚Ä™du + /// + public int StatusCode { get; set; } + + /// + /// Wiadomość bÅ‚Ä™du do pokazania + /// + public string Message { get; set; } + + public override string ToString() + { + return JsonSerializer.Serialize(this); + } + } +} diff --git a/SessionCompanion/SessionCompanion.ViewModels/ApiResponses/SuccessResponse.cs b/SessionCompanion/SessionCompanion.ViewModels/ApiResponses/SuccessResponse.cs new file mode 100644 index 0000000..4cefb98 --- /dev/null +++ b/SessionCompanion/SessionCompanion.ViewModels/ApiResponses/SuccessResponse.cs @@ -0,0 +1,28 @@ +namespace SessionCompanion.ViewModels.ApiResponses +{ + /// + /// Wiadomość mówiÄ…ca o poprawnym wykonaniu zadania + /// + public class SuccessResponse + { + /// + /// Konstruktor obiektu + /// + /// Wiadomość dotyczÄ…ca operacji + public SuccessResponse(string message) + { + this.SuccessCode = 200; + this.SuccessMessage = message; + } + + /// + /// Kod odpowiedzi, domyÅ›lnie nadawany jest 200 + /// + public int SuccessCode { get; set; } + + /// + /// Wiadomość dotyczÄ…ca wykoanania operacji + /// + public string SuccessMessage { get; set; } + } +} From db2de42824d7617bf43c92169893484528ba6b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20G=C3=B3reczny?= Date: Thu, 10 Dec 2020 17:34:46 +0100 Subject: [PATCH 7/8] =?UTF-8?q?ko=C5=84cowe=20poprawki?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ApiErrors/ErrorDetails.cs | 26 ------ .../EitherType/Either.cs | 80 ++++++++++++------- .../Configurations/ExceptionMiddleware.cs | 3 +- .../Controllers/CharacterController.cs | 5 +- 4 files changed, 56 insertions(+), 58 deletions(-) delete mode 100644 SessionCompanion/SessionCompanion.Extensions/ApiErrors/ErrorDetails.cs diff --git a/SessionCompanion/SessionCompanion.Extensions/ApiErrors/ErrorDetails.cs b/SessionCompanion/SessionCompanion.Extensions/ApiErrors/ErrorDetails.cs deleted file mode 100644 index e6ad261..0000000 --- a/SessionCompanion/SessionCompanion.Extensions/ApiErrors/ErrorDetails.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.Json; -using System.Threading.Tasks; - -namespace SessionCompanion.Extensions.ApiErrors -{ - public class ErrorDetails - { - /// - /// Kod bÅ‚Ä™du - /// - public int StatusCode { get; set; } - - /// - /// Wiadomość bÅ‚Ä™du do pokazania - /// - public string Message { get; set; } - - public override string ToString() - { - return JsonSerializer.Serialize(this); - } - } -} diff --git a/SessionCompanion/SessionCompanion.Extensions/EitherType/Either.cs b/SessionCompanion/SessionCompanion.Extensions/EitherType/Either.cs index ae83888..41ca6be 100644 --- a/SessionCompanion/SessionCompanion.Extensions/EitherType/Either.cs +++ b/SessionCompanion/SessionCompanion.Extensions/EitherType/Either.cs @@ -4,29 +4,58 @@ namespace SessionCompanion.Extensions.EitherType { public class Either { - private readonly TL left; - - private readonly TR right; - - private readonly bool isLeft; - + /// + /// Kontruktor dla lewej zmiennej + /// + /// Wartość lewej zmiennej public Either(TL left) { - this.left = left; - this.isLeft = true; + this.Left = left; + this.IsLeft = true; } + /// + /// Konstruktor dla prawej zmiennej + /// + /// Wartość prawej zmiennej public Either(TR right) { - this.right = right; - this.isLeft = false; + this.Right = right; + this.IsLeft = false; } + /// + /// Lewa zmienna + /// + public TL Left { get; } + + /// + /// Prawa zmienna + /// + public TR Right { get; } + + /// + /// Zmienna informujaca czy wykorzystana zostÄ…Å‚a zmienna lewa czy prawa + /// + public bool IsLeft { get; } + + /// + /// Tworzy obiekt typu Either wykorzystujÄ…c zmiennÄ… lewÄ… + /// + /// Wartość lewej zmiennej + public static implicit operator Either(TL left) => new Either(left); + + /// + /// Tworzy obiekt typu Either wykorzystujÄ…c zmiennÄ… prawÄ… + /// + /// Wartosć prawej zmiennej + public static implicit operator Either(TR right) => new Either(right); + /// /// Bazowa metoda dopasowania wzorów. /// JeÅ›li podana jest wartość lewa, to Match zwróci wynik lewej funkcji, w przeciwnym razie wynik prawej funkcji. /// - /// + /// Typ zwracanej wartoÅ›ci /// Lewa funkcja /// Prawa funkcja /// Wynik prawej/lewej funkcji @@ -42,28 +71,21 @@ namespace SessionCompanion.Extensions.EitherType throw new ArgumentNullException(nameof(rightFunc)); } - return this.isLeft ? leftFunc(this.left) : rightFunc(this.right); - } - - public void DoRight(Action rightAction) - { - if (rightAction == null) - { - throw new ArgumentNullException(nameof(rightAction)); - } - - if (!this.isLeft) - { - rightAction(this.right); - } + return this.IsLeft ? leftFunc(this.Left) : rightFunc(this.Right); } + /// + /// Funkcja ustala czy uzyta zostaÅ‚a lewa zmienna, jesli tak to zwraca jej wartość inaczej zwraca defaultowy obiekt + /// o typie takim jak lewa zmienna + /// + /// Wartosć lewej zmiennej lub defaultowÄ… wartość o typie lewej zmiennej public TL LeftOrDefault() => this.Match(l => l, r => default(TL)); + /// + /// Funkcja ustala czy uzyta zostaÅ‚a prawa zmienna, jesli tak to zwraca jej wartość inaczej zwraca defaultowy obiekt + /// o typie takim jak lewa zmienna + /// + /// Wartosć lewej zmiennej lub defaultowÄ… wartość o typie prawej zmiennej public TR RightOrDefault() => this.Match(l => default(TR), r => r); - - public static implicit operator Either(TL left) => new Either(left); - - public static implicit operator Either(TR right) => new Either(right); } } diff --git a/SessionCompanion/SessionCompanion/Configurations/ExceptionMiddleware.cs b/SessionCompanion/SessionCompanion/Configurations/ExceptionMiddleware.cs index a9ba919..b7b37bf 100644 --- a/SessionCompanion/SessionCompanion/Configurations/ExceptionMiddleware.cs +++ b/SessionCompanion/SessionCompanion/Configurations/ExceptionMiddleware.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using SessionCompanion.ViewModels.ApiResponses; namespace SessionCompanion.Configurations { @@ -33,7 +34,7 @@ namespace SessionCompanion.Configurations { context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; - return context.Response.WriteAsync(new ErrorDetails() + return context.Response.WriteAsync(new ErrorResponse() { StatusCode = context.Response.StatusCode, Message = exception.Message diff --git a/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs b/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs index 061f08d..3373e2e 100644 --- a/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs +++ b/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs @@ -2,10 +2,11 @@ using Microsoft.AspNetCore.Mvc; using SessionCompanion.Services.Interfaces; using SessionCompanion.ViewModels.CharacterViewModels; -using SessionCompanion.ApiReturn; namespace SessionCompanion.Controllers { + using SessionCompanion.Extensions.EitherType; + [Route("api/character")] [ApiController] public class CharacterController : Controller @@ -23,7 +24,7 @@ namespace SessionCompanion.Controllers /// Identyfikator postaci /// ViewModel Postaci [HttpGet("{id}")] - public async Task> Get(int id) + public async Task Get(int id) { return await _service.Get(id); } From 81aebe44dee551b14a6e25eab3f8cec194ad0db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20G=C3=B3reczny?= Date: Fri, 11 Dec 2020 11:10:51 +0100 Subject: [PATCH 8/8] SES-91 Added documentation and extra method --- .../EitherType/Either.cs | 28 +++ .../EitherType/EitherDocumentation.md | 184 ++++++++++++++++++ .../Controllers/CharacterController.cs | 2 - 3 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 SessionCompanion/SessionCompanion.Extensions/EitherType/EitherDocumentation.md diff --git a/SessionCompanion/SessionCompanion.Extensions/EitherType/Either.cs b/SessionCompanion/SessionCompanion.Extensions/EitherType/Either.cs index 41ca6be..c845eef 100644 --- a/SessionCompanion/SessionCompanion.Extensions/EitherType/Either.cs +++ b/SessionCompanion/SessionCompanion.Extensions/EitherType/Either.cs @@ -74,6 +74,34 @@ namespace SessionCompanion.Extensions.EitherType return this.IsLeft ? leftFunc(this.Left) : rightFunc(this.Right); } + /// + /// Bazowa metoda dopasowania wzorów. + /// JeÅ›li podana jest wartość lewa, to Match wykona lewÄ… funkcjÄ™, w przeciwnym razie wykona funkcjÄ™ prawÄ…. + /// + /// Lewa funkcja + /// Prawa funkcja + public void Match(Action leftFunc, Action rightFunc) + { + if (leftFunc == null) + { + throw new ArgumentNullException(nameof(leftFunc)); + } + + if (rightFunc == null) + { + throw new ArgumentNullException(nameof(rightFunc)); + } + + if (this.IsLeft) + { + leftFunc(this.Left); + } + else + { + rightFunc(this.Right); + } + } + /// /// Funkcja ustala czy uzyta zostaÅ‚a lewa zmienna, jesli tak to zwraca jej wartość inaczej zwraca defaultowy obiekt /// o typie takim jak lewa zmienna diff --git a/SessionCompanion/SessionCompanion.Extensions/EitherType/EitherDocumentation.md b/SessionCompanion/SessionCompanion.Extensions/EitherType/EitherDocumentation.md new file mode 100644 index 0000000..dfcca7c --- /dev/null +++ b/SessionCompanion/SessionCompanion.Extensions/EitherType/EitherDocumentation.md @@ -0,0 +1,184 @@ +# Either + +### Jak u¿ywaæ + +Either umo¿liwa nam zwrócenie z metody b¹dŸ nawet kontrolera, dwóch mo¿liwych wyników. +Dla u³atwienia zrozumienai poni¿ej podajê przyk³ady stosowania. + +Jako typ zmiennej zwracanej z api: +W tym przypadku wskazujemy, ¿e nasze api zwróci albo CharacterViewModel albo ErrorResponse +```cs +public async Task> Get(int id) +``` +Aby zwróciæ ten typ mamy dwie mo¿liwoœci. +Mo¿emy wywo³aæ metodê z serisu, która ma nam zwróciæ CharacterViewModel. +Nastêpnie sprawdziæ czy otrzymana wartoœæ CharacerViewModel zawiera jakiekolwiek dane i odpowiednio, jeœli tak to zwracamy otrzymany viewmodel a jeœli nie tworzymy ErrorResponse i zwracamy wynik: +```cs +public async Task> Get(int id) + { + Either result = await _service.Get(id); + + if (result.Left != null) + { + return result; + } + else + { + result = new ErrorResponse { StatusCode = 400, Message = "Coœ posz³o nie tak" }; + + return result; + } + } +``` +W przypadku jesli serwis nie znajdzie wartoœci otrzymamy: +```json +{ +"left":null, +"right":{ + "statusCode":400, + "message":"Coœ posz³o nie tak"}, +"isLeft":false} +``` + +Drugim sposobem jest zmiana dzia³ania serwisu: + +```cs +public async Task> GetCharacter(int id) + { + var repoResult = await this.Repository.Get(id); + if (repoResult != null) + { + return Mapper.Map(repoResult); + } + else + { + return new ErrorResponse() + { + StatusCode = 404, + Message = "Coœ posz³o nie tak" + }; + } + } +``` + +Wtedy kontroler wygl¹da tak : +```sh +public async Task> Get(int id) + { + return await this._service.GetCharacter(id); + } +``` + +### Przypisanie nowej wartoœci +Jeœli z jakiegoœpowodu bêdziemy chcieli zmieniæ wartoœæ obiektu Either, musimy dokonaæ tego w taki oto sposób: +```cs +UserViewModel user = new UserViewModel() { Id = 1, Nickname = "Testowy", Password = "Secret" }; +Either test = "asd"; + +// zmieniamy wartoœæ Either +test = user; + +// Warto zauwa¿yæ, ¿e mo¿emy zmieniæ wartoœæ obiektu znajdujacego siê wewn¹trz +// którejœ ze zmiennej o ile jest on publiczny +test.Left.Nickname = "test"; + +// Jednak jeœli dokonamy tego po zmianie wartoœci obietu na inny pomimo tego, ¿e +// dla kodu jest to ok, to nie zadzia³a to poprawnie, poniewa¿ wartoœæ starego obiektu +// jest zmieniana na null(dla boola na false) +test = "asd"; +test.Left.Nickname = "b³¹d"; + +``` + +### LeftOrDefault() oraz RightOrDefault() + +Zwracaj¹ one wartoœæ wybranej zmiennej b¹dŸ jej wartoœæ defaultow¹. +Dla wiekszoœci obiektów jest to null, wyjatkiem jest tutaj bool, który zwróci nam false. +```cs +var test = (Either)true; + +var a = test.LeftOrDefault(); // zwróci nam true + var b = test.RightOrDefault(); // zwróci nam null + +test = "asd"; + +var c = test.LeftOrDefault(); // zwróci nam false +var d = test.RightOrDefault(); // zwróci nam "asd" +``` + +### Match + +Funkcja ta pozwala nam na odpalenie odpowiedniej metody w zale¿noœci od tego jako typ zmiennej jest aktualnie przechowywany w obiekcie Either. Niestety ograniczeniem jest to, ze obie funkcje musza docelowo zwróciæ ten sam typ. +```cs +// ³adujemy userviewmodel do obiektu Either i wywo³ywamy matcha pdaj¹c dwie funkcje +test = user; +// zwwrócny zostanie string "Test1" +test.Match(this.Test1, this.Test2); + +// ³adujemy stringa do obiektu Either i wywo³ywamy matcha pdaj¹c dwie funkcje +test = "asd"; +// zwwrócny zostanie string "Test2" +test.Match(this.Test1, this.Test2); + +public string Test1(UserViewModel viewModel) +{ + return "Test1"; +} + + public string Test2(string text) +{ + return "Test2"; +} +``` + +Warto zauwa¿yæ, ¿e mo¿emy wykorzystaæ tutaj lambde by rozszerzyæ nasze mo¿liwoœci: +```cs +test = "asd"; + +test.Match( + Test1, + second => + { + int z = Test2(second); + // tutaj mo¿emy robiæ ju¿ co nam siê tylko podoba + // pamiêtaæ nale¿y ze finalnie musimy coœ zwróciæ + // chyba, ¿e nasze obie funkcje s¹ typu void + return z.ToString(); +}); + +public string Test1(UserViewModel viewModel) +{ + return "Test1"; +} + + public int Test2(string text) +{ + return 12; +} +``` + +Mo¿emy te¿ podaæ jedna funkcjê typu void a drug¹ typu innego np. string albo int: +```cs +y = ""; +test = "asd"; + +test.Match( + Test1, + second => + { + var x = this.Test2(second); + //jednak nie ma mo¿liwoœci zwrócenia wartoœci + // mo¿emy za to zwróciæ wyniki do zewnêtrznej zmiennej + y = x; +}); + +public void Test1(UserViewModel viewModel) +{ + //...coœ robi +} + + public string Test2(string text) +{ + return "Test2"; +} +``` \ No newline at end of file diff --git a/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs b/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs index 3373e2e..49eb93b 100644 --- a/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs +++ b/SessionCompanion/SessionCompanion/Controllers/CharacterController.cs @@ -5,8 +5,6 @@ using SessionCompanion.ViewModels.CharacterViewModels; namespace SessionCompanion.Controllers { - using SessionCompanion.Extensions.EitherType; - [Route("api/character")] [ApiController] public class CharacterController : Controller