From 8432b42ddc820112747a9af1331391fbd9085dbb Mon Sep 17 00:00:00 2001 From: Kyle McMaster Date: Wed, 22 Feb 2023 22:49:54 -0500 Subject: [PATCH] Update TargetFramework to .NET 7 (#112) * Update TargetFramework to .NET 7 * Update projects to reflect modern .NET patterns * Update README * Update package versions from 4.2.0 -> 7.0.0 * rename method * update packages * Update release notes and CI pipelines for .NET 7 * Use .NEt 7.x and update unit test project to .NET 7 * update package release notes --- .github/workflows/dotnetcore.yml | 2 +- .github/workflows/publish-result-related.yml | 2 +- .github/workflows/publish-result.yml | 2 +- Ardalis.Result.sln | 13 +-- README.md | 18 ++-- .../Ardalis.Result.Sample.Core.csproj | 4 +- .../Ardalis.Result.Sample.UnitTests.csproj | 8 +- ...lt.SampleMinimalApi.FunctionalTests.csproj | 8 +- .../Ardalis.Result.SampleMinimalApi.csproj | 4 +- .../Program.cs | 2 - ...is.Result.SampleWeb.FunctionalTests.csproj | 8 +- .../PersonControllerDelete.cs | 4 +- .../WeatherForecastControllerPost.cs | 4 +- .../Ardalis.Result.SampleWeb.csproj | 6 +- .../Pages/Index.cshtml | 2 +- sample/Ardalis.Result.SampleWeb/Program.cs | 77 ++++++++++++++--- sample/Ardalis.Result.SampleWeb/Startup.cs | 82 ------------------- sample/Ardalis.Result.SampleWeb/WebMarker.cs | 6 ++ .../Ardalis.Result.AspNetCore.csproj | 8 +- .../MinimalApiResultExtensions.cs | 2 +- .../Ardalis.Result.FluentValidation.csproj | 8 +- src/Ardalis.Result/Ardalis.Result.csproj | 6 +- ...Ardalis.Result.AspNetCore.UnitTests.csproj | 10 +-- .../BaseResultConventionTest.cs | 2 +- .../ResultConventionDefaultResultStatusMap.cs | 48 +++++------ ...onventionDefaultResultStatusMapModified.cs | 32 ++++---- .../ResultConventionExpectedFailures.cs | 6 +- .../Ardalis.Result.UnitTests.csproj | 6 +- 28 files changed, 177 insertions(+), 203 deletions(-) delete mode 100644 sample/Ardalis.Result.SampleWeb/Startup.cs create mode 100644 sample/Ardalis.Result.SampleWeb/WebMarker.cs diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index 965664c..d62e598 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -17,7 +17,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: '7.0.x' + dotnet-version: '7.x' - name: Install dependencies run: dotnet restore - name: Build diff --git a/.github/workflows/publish-result-related.yml b/.github/workflows/publish-result-related.yml index ac5cc19..f4ed231 100644 --- a/.github/workflows/publish-result-related.yml +++ b/.github/workflows/publish-result-related.yml @@ -14,7 +14,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: '7.x' - name: Install dependencies run: dotnet restore - name: Build diff --git a/.github/workflows/publish-result.yml b/.github/workflows/publish-result.yml index d12a142..e02770b 100644 --- a/.github/workflows/publish-result.yml +++ b/.github/workflows/publish-result.yml @@ -13,7 +13,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: '7.x' - name: Install dependencies run: dotnet restore - name: Build diff --git a/Ardalis.Result.sln b/Ardalis.Result.sln index 92fd359..fdcb6c7 100644 --- a/Ardalis.Result.sln +++ b/Ardalis.Result.sln @@ -25,12 +25,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Result.Sample.Core" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Result.FluentValidation", "src\Ardalis.Result.FluentValidation\Ardalis.Result.FluentValidation.csproj", "{43443B4B-2305-4CDF-A7A4-32A80ED1D19B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Result.AspNetCore.UnitTests", "tests\Ardalis.Result.AspNetCore.UnitTests\Ardalis.Result.AspNetCore.UnitTests.csproj", "{0BDA82F9-3602-4705-8DCD-A4724CAAF800}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Result.SampleMinimalApi", "sample\Ardalis.Result.SampleMinimalApi\Ardalis.Result.SampleMinimalApi.csproj", "{60860685-37BB-47D9-B0DC-6FE7F0DB2AE5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Result.SampleMinimalApi.FunctionalTests", "sample\Ardalis.Result.SampleMinimalApi.FunctionalTests\Ardalis.Result.SampleMinimalApi.FunctionalTests.csproj", "{A9769533-C9B2-4AD4-8B24-70C474D8EBB0}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Result.AspNetCore.UnitTests", "tests\Ardalis.Result.AspNetCore.UnitTests\Ardalis.Result.AspNetCore.UnitTests.csproj", "{C522FE42-BBEF-46A7-9E3E-44EA8339AF2E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -69,10 +69,6 @@ Global {43443B4B-2305-4CDF-A7A4-32A80ED1D19B}.Debug|Any CPU.Build.0 = Debug|Any CPU {43443B4B-2305-4CDF-A7A4-32A80ED1D19B}.Release|Any CPU.ActiveCfg = Release|Any CPU {43443B4B-2305-4CDF-A7A4-32A80ED1D19B}.Release|Any CPU.Build.0 = Release|Any CPU - {0BDA82F9-3602-4705-8DCD-A4724CAAF800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0BDA82F9-3602-4705-8DCD-A4724CAAF800}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0BDA82F9-3602-4705-8DCD-A4724CAAF800}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0BDA82F9-3602-4705-8DCD-A4724CAAF800}.Release|Any CPU.Build.0 = Release|Any CPU {60860685-37BB-47D9-B0DC-6FE7F0DB2AE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {60860685-37BB-47D9-B0DC-6FE7F0DB2AE5}.Debug|Any CPU.Build.0 = Debug|Any CPU {60860685-37BB-47D9-B0DC-6FE7F0DB2AE5}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -81,6 +77,10 @@ Global {A9769533-C9B2-4AD4-8B24-70C474D8EBB0}.Debug|Any CPU.Build.0 = Debug|Any CPU {A9769533-C9B2-4AD4-8B24-70C474D8EBB0}.Release|Any CPU.ActiveCfg = Release|Any CPU {A9769533-C9B2-4AD4-8B24-70C474D8EBB0}.Release|Any CPU.Build.0 = Release|Any CPU + {C522FE42-BBEF-46A7-9E3E-44EA8339AF2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C522FE42-BBEF-46A7-9E3E-44EA8339AF2E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C522FE42-BBEF-46A7-9E3E-44EA8339AF2E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C522FE42-BBEF-46A7-9E3E-44EA8339AF2E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -96,6 +96,7 @@ Global {43443B4B-2305-4CDF-A7A4-32A80ED1D19B} = {865A74CD-F478-4AA5-AFA5-6C26FB38B849} {60860685-37BB-47D9-B0DC-6FE7F0DB2AE5} = {FA061DC6-61B7-401F-87A4-D338B396CCD9} {A9769533-C9B2-4AD4-8B24-70C474D8EBB0} = {FA061DC6-61B7-401F-87A4-D338B396CCD9} + {C522FE42-BBEF-46A7-9E3E-44EA8339AF2E} = {42693FB1-04E1-4635-B249-E1847609E801} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7CD0ED8C-3B1C-4F16-8B8D-3D8F1A8F1A5A} diff --git a/README.md b/README.md index cb1d3e2..beaf817 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ public async Task>(int customerId) Another approach is to return a `Tuple` of the expected result along with other things, like a status code and additional failure mode metadata. While tuples can be great for individual, flexible responses, they're not as good for having a single, standard, reusable approach to a problem. -The result pattern provides a standard, reusable way to return both success as well as multiple kinds of non-success responses from .NET services in a way that can easily be mapped to API response types. Although the [Ardalis.Result](https://www.nuget.org/packages/Ardalis.Result/) package has no dependencies on ASP.NET Core and can be used from any .NET Core application, the [Ardalis.Result.AspNetCore](https://www.nuget.org/packages/Ardalis.Result.AspNetCore/) companion package includes resources to enhance the use of this pattern within ASP.NET Core web API applications. +The Result pattern provides a standard, reusable way to return both success as well as multiple kinds of non-success responses from .NET services in a way that can easily be mapped to API response types. Although the [Ardalis.Result](https://www.nuget.org/packages/Ardalis.Result/) package has no dependencies on ASP.NET Core and can be used from any .NET Core application, the [Ardalis.Result.AspNetCore](https://www.nuget.org/packages/Ardalis.Result.AspNetCore/) companion package includes resources to enhance the use of this pattern within ASP.NET Core web API applications. ## Sample Usage @@ -164,16 +164,16 @@ public ActionResult CreateSummaryForecast([FromBody] } ``` -## Asp Net API Metadata +## ASP.NET API Metadata -By default, Asp Net Core and Api Explorer know nothing about `[TranslateResultToActionResult]` and what it is doing. To reflect `[TranslateResultToActionResult]` behavior in metadata generated by Api Explorer (which is then used by tools like Swashbuckle, NSwag etc.), you can use `ResultConvention`: +By default, Asp Net Core and API Explorer know nothing about `[TranslateResultToActionResult]` and what it is doing. To reflect `[TranslateResultToActionResult]` behavior in metadata generated by API Explorer (which is then used by tools like Swashbuckle, NSwag etc.), you can use `ResultConvention`: ```csharp services.AddControllers(mvcOptions => mvcOptions.AddDefaultResultConvention()); ``` This will add `[ProducesResponseType]` for every known `ResultStatus` to every endpoint marked with `[TranslateResultToActionResult]`. -To customize ResultConvention behavior, one may use `AddResultConvention` method: +To customize ResultConvention behavior, one may use the `AddResultConvention` method: ```csharp services.AddControllers(mvcOptions => mvcOptions @@ -182,9 +182,9 @@ services.AddControllers(mvcOptions => mvcOptions )); ``` -This code is functionally equivalent to previous example. +This code is functionally equivalent to the previous example. -From here you can modify ResultStatus-to-HttpStatusCode mapping +From here you can modify the ResultStatus to HttpStatusCode mapping ```csharp services.AddControllers(mvcOptions => mvcOptions @@ -211,7 +211,7 @@ services.AddControllers(mvcOptions => mvcOptions )); ``` -Alternatively, you can specify which (failure) result statuses are expected from certain endpoint: +Alternatively, you can specify which (failure) result statuses are expected from a certain endpoint: ```csharp [TranslateResultToActionResult()] @@ -223,9 +223,9 @@ public Result RemovePerson(int id) } ``` -`!!!` If you list certain result status in `ExpectedFailures`, it must be configured in `ResultConvention` on startup. +`!!!` If you list a certain Result status in `ExpectedFailures`, it must be configured in `ResultConvention` on startup. -Another configurability feature is what part of Result object is returned in case of specific failure: +Another configurable feature is what part of the Result object is returned in case of specific failure: ```csharp services.AddControllers(mvcOptions => mvcOptions diff --git a/sample/Ardalis.Result.Sample.Core/Ardalis.Result.Sample.Core.csproj b/sample/Ardalis.Result.Sample.Core/Ardalis.Result.Sample.Core.csproj index a438981..f9b1c8a 100644 --- a/sample/Ardalis.Result.Sample.Core/Ardalis.Result.Sample.Core.csproj +++ b/sample/Ardalis.Result.Sample.Core/Ardalis.Result.Sample.Core.csproj @@ -1,13 +1,13 @@  - net6.0 + net7.0 Ardalis.Result.Sample.Core Ardalis.Result.Sample.Core - + diff --git a/sample/Ardalis.Result.Sample.UnitTests/Ardalis.Result.Sample.UnitTests.csproj b/sample/Ardalis.Result.Sample.UnitTests/Ardalis.Result.Sample.UnitTests.csproj index a076b6f..3b1c436 100644 --- a/sample/Ardalis.Result.Sample.UnitTests/Ardalis.Result.Sample.UnitTests.csproj +++ b/sample/Ardalis.Result.Sample.UnitTests/Ardalis.Result.Sample.UnitTests.csproj @@ -1,14 +1,14 @@ - + - net6.0 + net7.0 false - - + + all diff --git a/sample/Ardalis.Result.SampleMinimalApi.FunctionalTests/Ardalis.Result.SampleMinimalApi.FunctionalTests.csproj b/sample/Ardalis.Result.SampleMinimalApi.FunctionalTests/Ardalis.Result.SampleMinimalApi.FunctionalTests.csproj index 93f426e..e4c9099 100644 --- a/sample/Ardalis.Result.SampleMinimalApi.FunctionalTests/Ardalis.Result.SampleMinimalApi.FunctionalTests.csproj +++ b/sample/Ardalis.Result.SampleMinimalApi.FunctionalTests/Ardalis.Result.SampleMinimalApi.FunctionalTests.csproj @@ -1,13 +1,13 @@ - + - net6.0 + net7.0 false - - + + all diff --git a/sample/Ardalis.Result.SampleMinimalApi/Ardalis.Result.SampleMinimalApi.csproj b/sample/Ardalis.Result.SampleMinimalApi/Ardalis.Result.SampleMinimalApi.csproj index 53e6ae2..1ad1caf 100644 --- a/sample/Ardalis.Result.SampleMinimalApi/Ardalis.Result.SampleMinimalApi.csproj +++ b/sample/Ardalis.Result.SampleMinimalApi/Ardalis.Result.SampleMinimalApi.csproj @@ -1,7 +1,7 @@  - net6.0 + net7.0 enable enable @@ -12,7 +12,7 @@ - TargetFramework=net6.0 + TargetFramework=net7.0 diff --git a/sample/Ardalis.Result.SampleMinimalApi/Program.cs b/sample/Ardalis.Result.SampleMinimalApi/Program.cs index 7f71480..65d7b2f 100644 --- a/sample/Ardalis.Result.SampleMinimalApi/Program.cs +++ b/sample/Ardalis.Result.SampleMinimalApi/Program.cs @@ -6,8 +6,6 @@ var builder = WebApplication.CreateBuilder(args); -// Add services to the container. -// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddScoped(); diff --git a/sample/Ardalis.Result.SampleWeb.FunctionalTests/Ardalis.Result.SampleWeb.FunctionalTests.csproj b/sample/Ardalis.Result.SampleWeb.FunctionalTests/Ardalis.Result.SampleWeb.FunctionalTests.csproj index 996d483..01dd992 100644 --- a/sample/Ardalis.Result.SampleWeb.FunctionalTests/Ardalis.Result.SampleWeb.FunctionalTests.csproj +++ b/sample/Ardalis.Result.SampleWeb.FunctionalTests/Ardalis.Result.SampleWeb.FunctionalTests.csproj @@ -1,14 +1,14 @@ - + - net6.0 + net7.0 false - - + + all diff --git a/sample/Ardalis.Result.SampleWeb.FunctionalTests/PersonControllerDelete.cs b/sample/Ardalis.Result.SampleWeb.FunctionalTests/PersonControllerDelete.cs index 1bbcfe2..ad20e4d 100644 --- a/sample/Ardalis.Result.SampleWeb.FunctionalTests/PersonControllerDelete.cs +++ b/sample/Ardalis.Result.SampleWeb.FunctionalTests/PersonControllerDelete.cs @@ -8,7 +8,7 @@ namespace Ardalis.Result.SampleWeb.FunctionalTests; -public class PersonControllerDelete : IClassFixture> +public class PersonControllerDelete : IClassFixture> { private const string MEDIATR_CONTROLLER_POST_ROUTE = "/mediatr/person/remove/{0}"; private const string CONTROLLER_POST_ROUTE = "/person/remove/{0}"; @@ -16,7 +16,7 @@ public class PersonControllerDelete : IClassFixture factory) + public PersonControllerDelete(WebApplicationFactory factory) { _client = factory.CreateClient(); } diff --git a/sample/Ardalis.Result.SampleWeb.FunctionalTests/WeatherForecastControllerPost.cs b/sample/Ardalis.Result.SampleWeb.FunctionalTests/WeatherForecastControllerPost.cs index 65c8a4c..ece3b89 100644 --- a/sample/Ardalis.Result.SampleWeb.FunctionalTests/WeatherForecastControllerPost.cs +++ b/sample/Ardalis.Result.SampleWeb.FunctionalTests/WeatherForecastControllerPost.cs @@ -13,13 +13,13 @@ namespace Ardalis.Result.SampleWeb.FunctionalTests; -public class WeatherForecastControllerPost : IClassFixture> +public class WeatherForecastControllerPost : IClassFixture> { private const string CONTROLLER_POST_ROUTE = "/weatherforecast/create"; private const string ENDPOINT_POST_ROUTE = "/forecast/new"; private readonly HttpClient _client; - public WeatherForecastControllerPost(WebApplicationFactory factory) + public WeatherForecastControllerPost(WebApplicationFactory factory) { _client = factory.CreateClient(); } diff --git a/sample/Ardalis.Result.SampleWeb/Ardalis.Result.SampleWeb.csproj b/sample/Ardalis.Result.SampleWeb/Ardalis.Result.SampleWeb.csproj index b299bcc..6fbb4a4 100644 --- a/sample/Ardalis.Result.SampleWeb/Ardalis.Result.SampleWeb.csproj +++ b/sample/Ardalis.Result.SampleWeb/Ardalis.Result.SampleWeb.csproj @@ -1,13 +1,13 @@  - net6.0 + net7.0 - - + + diff --git a/sample/Ardalis.Result.SampleWeb/Pages/Index.cshtml b/sample/Ardalis.Result.SampleWeb/Pages/Index.cshtml index 99b4a76..81c0cbc 100644 --- a/sample/Ardalis.Result.SampleWeb/Pages/Index.cshtml +++ b/sample/Ardalis.Result.SampleWeb/Pages/Index.cshtml @@ -20,7 +20,7 @@

WeatherForecast:

    -
  • PostalCode 55555 should work (200 OK)
  • +
  • PostalCode 55555 should work (201 Created)
  • PostalCode "" should fail (400 Bad Request with error list (required))
  • PostalCode "NotFound" should return (404 Not Found)
  • PostalCode "This is too long." should return (400 Bad Request with error list)
  • diff --git a/sample/Ardalis.Result.SampleWeb/Program.cs b/sample/Ardalis.Result.SampleWeb/Program.cs index ba2f09b..544ffe2 100644 --- a/sample/Ardalis.Result.SampleWeb/Program.cs +++ b/sample/Ardalis.Result.SampleWeb/Program.cs @@ -1,19 +1,70 @@ +using Ardalis.Result; +using Ardalis.Result.AspNetCore; +using Ardalis.Result.Sample.Core.Services; +using Ardalis.Result.SampleWeb.MediatrApi; +using MediatR; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Localization; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using System.Collections.Generic; +using System.Globalization; +using System.Net; -namespace Ardalis.Result.SampleWeb; +var builder = WebApplication.CreateBuilder(args); -public class Program +var webAssembly = typeof(Program).Assembly; +builder.Services.AddMediatR(webAssembly); +builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>)); + +builder.Services.AddControllers(mvcOptions => mvcOptions + .AddResultConvention(resultStatusMap => resultStatusMap + .AddDefaultMap() + .For(ResultStatus.Ok, HttpStatusCode.OK, resultStatusOptions => resultStatusOptions + .For("POST", HttpStatusCode.Created) + .For("DELETE", HttpStatusCode.NoContent)) + .Remove(ResultStatus.Forbidden) + .Remove(ResultStatus.Unauthorized) + )); + +builder.Services.AddRazorPages(); +builder.Services.AddLocalization(opt => { opt.ResourcesPath = "Resources"; }); +builder.Services.Configure(options => +{ + var supportedCultures = new List + { + new CultureInfo("en-US"), + new CultureInfo("de-DE"), + }; + options.DefaultRequestCulture = new RequestCulture("en-US"); + options.SupportedCultures = supportedCultures; + options.SupportedUICultures = supportedCultures; +}); + +builder.Services.AddSwaggerGen(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); + +var app = builder.Build(); + +if (builder.Environment.IsDevelopment()) { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); + app.UseDeveloperExceptionPage(); } + +app.UseHttpsRedirection(); + +app.UseRouting(); +app.UseSwagger(); +app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1")); + +var options = app.Services.GetService>(); +app.UseRequestLocalization(options.Value); + +app.MapControllers(); +app.MapRazorPages(); + +app.Run(); \ No newline at end of file diff --git a/sample/Ardalis.Result.SampleWeb/Startup.cs b/sample/Ardalis.Result.SampleWeb/Startup.cs deleted file mode 100644 index 19dad88..0000000 --- a/sample/Ardalis.Result.SampleWeb/Startup.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Ardalis.Result.AspNetCore; -using Ardalis.Result.Sample.Core.Services; -using Ardalis.Result.SampleWeb.MediatrApi; -using MediatR; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Localization; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; -using System.Collections.Generic; -using System.Globalization; -using System.Net; - -namespace Ardalis.Result.SampleWeb; - -public class Startup -{ - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - public void ConfigureServices(IServiceCollection services) - { - var webAssembly = typeof(Startup).Assembly; - services.AddMediatR(webAssembly); - services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>)); - services.AddControllers(mvcOptions => mvcOptions - .AddResultConvention(resultStatusMap => resultStatusMap - .AddDefaultMap() - .For(ResultStatus.Ok, HttpStatusCode.OK, resultStatusOptions => resultStatusOptions - .For("POST", HttpStatusCode.Created) - .For("DELETE", HttpStatusCode.NoContent)) - .Remove(ResultStatus.Forbidden) - .Remove(ResultStatus.Unauthorized) - )); - services.AddRazorPages(); - services.AddLocalization(opt => { opt.ResourcesPath = "Resources"; }); - services.Configure(options => - { - List supportedCultures = new List - { - new CultureInfo("en-US"), - new CultureInfo("de-DE"), - }; - options.DefaultRequestCulture = new RequestCulture("en-US"); - options.SupportedCultures = supportedCultures; - options.SupportedUICultures = supportedCultures; - }); - services.AddSwaggerGen(); - - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - app.UseHttpsRedirection(); - - app.UseRouting(); - app.UseSwagger(); - app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1")); - - var options = app.ApplicationServices.GetService>(); - app.UseRequestLocalization(options.Value); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - endpoints.MapRazorPages(); - }); - } -} diff --git a/sample/Ardalis.Result.SampleWeb/WebMarker.cs b/sample/Ardalis.Result.SampleWeb/WebMarker.cs new file mode 100644 index 0000000..3e7c56e --- /dev/null +++ b/sample/Ardalis.Result.SampleWeb/WebMarker.cs @@ -0,0 +1,6 @@ +namespace Ardalis.Result.SampleWeb +{ + public class WebMarker + { + } +} diff --git a/src/Ardalis.Result.AspNetCore/Ardalis.Result.AspNetCore.csproj b/src/Ardalis.Result.AspNetCore/Ardalis.Result.AspNetCore.csproj index 9a8f8a6..cc9d63b 100644 --- a/src/Ardalis.Result.AspNetCore/Ardalis.Result.AspNetCore.csproj +++ b/src/Ardalis.Result.AspNetCore/Ardalis.Result.AspNetCore.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net6.0 + netstandard2.0;net7.0 Ardalis.Result.AspNetCore Ardalis.Result.AspNetCore true @@ -13,8 +13,8 @@ https://github.com/ardalis/result result pattern web api aspnetcore mvc MIT - Added extensions to translate to IResult in minimal APIs - 4.2.0 + PRs 92 and 112. Adding support for .NET 7 and ability to improve Swagger/OpenAPI specifications when using the TranslateResultToActionResult attribute. + 7.0.0 Ardalis.Result.AspNetCore icon.png true @@ -25,7 +25,7 @@ - + diff --git a/src/Ardalis.Result.AspNetCore/MinimalApiResultExtensions.cs b/src/Ardalis.Result.AspNetCore/MinimalApiResultExtensions.cs index 7f64324..c679121 100644 --- a/src/Ardalis.Result.AspNetCore/MinimalApiResultExtensions.cs +++ b/src/Ardalis.Result.AspNetCore/MinimalApiResultExtensions.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER namespace Ardalis.Result.AspNetCore; public static partial class ResultExtensions { diff --git a/src/Ardalis.Result.FluentValidation/Ardalis.Result.FluentValidation.csproj b/src/Ardalis.Result.FluentValidation/Ardalis.Result.FluentValidation.csproj index 66e3630..360798e 100644 --- a/src/Ardalis.Result.FluentValidation/Ardalis.Result.FluentValidation.csproj +++ b/src/Ardalis.Result.FluentValidation/Ardalis.Result.FluentValidation.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net6.0 + netstandard2.0;net7.0 Ardalis.Result.FluentValidation Ardalis.Result.FluentValidation true @@ -13,8 +13,8 @@ https://github.com/ardalis/result result;pattern;web;api;aspnetcore;mvc;FluentValidation;Validation MIT - Updating dependencies. - 4.2.0 + PRs 92 and 112. Adding support for .NET 7. + 7.0.0 Ardalis.Result.FluentValidation icon.png true @@ -22,7 +22,7 @@ - + diff --git a/src/Ardalis.Result/Ardalis.Result.csproj b/src/Ardalis.Result/Ardalis.Result.csproj index 7a0f5ab..e26470d 100644 --- a/src/Ardalis.Result/Ardalis.Result.csproj +++ b/src/Ardalis.Result/Ardalis.Result.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net6.0 + netstandard2.0;net7.0 Ardalis.Result Ardalis.Result true @@ -13,8 +13,8 @@ https://github.com/ardalis/result result pattern web api aspnetcore mvc MIT - PRs 103,107,108. Adding extensions for minimal APIs, mapping NotFound errors, package updates. - 4.2.0 + PRs 92 and 112. Adding support for .NET 7 + 7.0.0 Ardalis.Result icon.png true diff --git a/tests/Ardalis.Result.AspNetCore.UnitTests/Ardalis.Result.AspNetCore.UnitTests.csproj b/tests/Ardalis.Result.AspNetCore.UnitTests/Ardalis.Result.AspNetCore.UnitTests.csproj index 104f984..ba524fa 100644 --- a/tests/Ardalis.Result.AspNetCore.UnitTests/Ardalis.Result.AspNetCore.UnitTests.csproj +++ b/tests/Ardalis.Result.AspNetCore.UnitTests/Ardalis.Result.AspNetCore.UnitTests.csproj @@ -1,19 +1,19 @@ - net6.0 + net7.0 enable enable - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Ardalis.Result.AspNetCore.UnitTests/BaseResultConventionTest.cs b/tests/Ardalis.Result.AspNetCore.UnitTests/BaseResultConventionTest.cs index b8c2880..5a57b9a 100644 --- a/tests/Ardalis.Result.AspNetCore.UnitTests/BaseResultConventionTest.cs +++ b/tests/Ardalis.Result.AspNetCore.UnitTests/BaseResultConventionTest.cs @@ -7,7 +7,7 @@ namespace Ardalis.Result.AspNetCore.UnitTests; public class BaseResultConventionTest { - protected bool IsProducesResponseTypeAttribute(IFilterMetadata filterMetadata, int statusCode, Type type) + protected bool ProducesResponseTypeAttribute(IFilterMetadata filterMetadata, int statusCode, Type type) { return filterMetadata is ProducesResponseTypeAttribute attr && attr.StatusCode == statusCode && attr.Type == type; diff --git a/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionDefaultResultStatusMap.cs b/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionDefaultResultStatusMap.cs index e11f0cc..0f6e203 100644 --- a/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionDefaultResultStatusMap.cs +++ b/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionDefaultResultStatusMap.cs @@ -20,12 +20,12 @@ public void TranslateAttributeOnAction() Assert.Equal(6, actionModel.Filters.Where(f => f is ProducesResponseTypeAttribute).Count()); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 204, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 401, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 403, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 204, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 401, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 403, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); } [Fact] @@ -42,12 +42,12 @@ public void TranslateAttributeOnController() Assert.Equal(6, actionModel.Filters.Where(f => f is ProducesResponseTypeAttribute).Count()); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 204, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 401, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 403, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 204, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 401, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 403, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); } [Fact] @@ -79,12 +79,12 @@ public void ExistingProducesResponseTypeAttributePreserved() Assert.Equal(6, actionModel.Filters.Where(f => f is ProducesResponseTypeAttribute).Count()); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 204, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 400, typeof(IEnumerable))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 401, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 403, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 204, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 400, typeof(IEnumerable))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 401, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 403, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); } [Theory] @@ -103,11 +103,11 @@ public void ResultWithValue(string actionName, Type expectedType) Assert.Equal(6, actionModel.Filters.Where(f => f is ProducesResponseTypeAttribute).Count()); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 200, expectedType)); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 401, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 403, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 200, expectedType)); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 401, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 403, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); } } diff --git a/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionDefaultResultStatusMapModified.cs b/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionDefaultResultStatusMapModified.cs index f0b69d7..c3574ea 100644 --- a/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionDefaultResultStatusMapModified.cs +++ b/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionDefaultResultStatusMapModified.cs @@ -23,10 +23,10 @@ public void RemoveResultStatus() Assert.Equal(4, actionModel.Filters.Where(f => f is ProducesResponseTypeAttribute).Count()); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 204, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 204, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); } [Fact] @@ -45,12 +45,12 @@ public void ChangeResultStatus() Assert.Equal(6, actionModel.Filters.Where(f => f is ProducesResponseTypeAttribute).Count()); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 204, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 401, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 403, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 500, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 204, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 401, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 403, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 500, typeof(void))); } [Theory] @@ -81,11 +81,11 @@ public void ChangeResultStatus_ForSpecificMethods(string actionName, Type expect Assert.Equal(6, actionModel.Filters.Where(f => f is ProducesResponseTypeAttribute).Count()); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, expectedStatusCode, expectedType)); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 401, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 403, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, expectedStatusCode, expectedType)); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 401, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 403, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 422, typeof(ProblemDetails))); } } diff --git a/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionExpectedFailures.cs b/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionExpectedFailures.cs index 2322d7a..084661e 100644 --- a/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionExpectedFailures.cs +++ b/tests/Ardalis.Result.AspNetCore.UnitTests/ResultConventionExpectedFailures.cs @@ -22,9 +22,9 @@ public void DefaultResultStatusMap() Assert.Equal(3, actionModel.Filters.Where(f => f is ProducesResponseTypeAttribute).Count()); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 204, typeof(void))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); - Assert.Contains(actionModel.Filters, f => IsProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 204, typeof(void))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 404, typeof(ProblemDetails))); + Assert.Contains(actionModel.Filters, f => ProducesResponseTypeAttribute(f, 400, typeof(ValidationProblemDetails))); } [Fact] diff --git a/tests/Ardalis.Result.UnitTests/Ardalis.Result.UnitTests.csproj b/tests/Ardalis.Result.UnitTests/Ardalis.Result.UnitTests.csproj index 31f244f..7ebf4c0 100644 --- a/tests/Ardalis.Result.UnitTests/Ardalis.Result.UnitTests.csproj +++ b/tests/Ardalis.Result.UnitTests/Ardalis.Result.UnitTests.csproj @@ -1,14 +1,14 @@  - net6.0 + net7.0 false - - + + all