Repository: Elfocrash/DotnetDocsShow.MinimalApis Branch: main Commit: 9513e4f6b511 Files: 76 Total size: 61.0 KB Directory structure: gitextract_9kootkau/ ├── .gitignore ├── DotnetDocsShow.Extensions.Validation/ │ ├── Customers/ │ │ ├── Customer.cs │ │ ├── CustomerEndpoints.cs │ │ ├── CustomerService.cs │ │ ├── CustomerValidation.cs │ │ └── ICustomerService.cs │ ├── DotnetDocsShow.Extensions.Validation.csproj │ ├── IAssemblyMarker.cs │ ├── Program.cs │ └── ValidationExtensions.cs ├── DotnetDocsShow.Intro.MinimalApi/ │ ├── DotnetDocsShow.Intro.MinimalApi.csproj │ └── Program.cs ├── DotnetDocsShow.MinimalApiTests.Structured/ │ ├── DotnetDocsShow.MinimalApiTests.Structured.csproj │ ├── EndpointDefinitionExtensions.cs │ ├── EndpointDefinitions/ │ │ ├── CustomerEndpointDefinition.cs │ │ └── SwaggerEndpointDefinition.cs │ ├── IEndpointDefinition.cs │ ├── Models/ │ │ └── Customer.cs │ ├── Program.cs │ └── Services/ │ ├── CustomerService.cs │ └── ICustomerService.cs ├── DotnetDocsShow.NewWebApi/ │ ├── Controllers/ │ │ └── WeatherForecastController.cs │ ├── DotnetDocsShow.NewWebApi.csproj │ ├── Program.cs │ ├── Properties/ │ │ └── launchSettings.json │ ├── WeatherForecast.cs │ ├── appsettings.Development.json │ └── appsettings.json ├── DotnetDocsShow.OldWebApi/ │ ├── Controllers/ │ │ └── WeatherForecastController.cs │ ├── DotnetDocsShow.OldWebApi.csproj │ ├── Program.cs │ ├── Properties/ │ │ └── launchSettings.json │ ├── Startup.cs │ ├── WeatherForecast.cs │ ├── appsettings.Development.json │ └── appsettings.json ├── DotnetDocsShow.PerformanceTests/ │ ├── DotnetDocsShow.PerformanceTests.csproj │ └── Program.cs ├── DotnetDocsShow.Structured.Extensions/ │ ├── Customers/ │ │ ├── Customer.cs │ │ ├── CustomerEndpoints.cs │ │ ├── CustomerService.cs │ │ └── ICustomerService.cs │ ├── DotnetDocsShow.Structured.Extensions.csproj │ └── Program.cs ├── DotnetDocsShow.Structured.Mediator/ │ ├── DotnetDocsShow.Structured.Mediator.csproj │ ├── Handlers/ │ │ ├── CreateCustomerRequestHandler.cs │ │ ├── DeleteCustomerByIdRequestHandler.cs │ │ ├── GetAllCustomersRequestHandler.cs │ │ └── GetCustomerByIdRequestHandler.cs │ ├── Models/ │ │ └── Customer.cs │ ├── Program.cs │ └── Services/ │ ├── CustomerService.cs │ └── ICustomerService.cs ├── DotnetDocsShow.Structured.Scanning/ │ ├── DotnetDocsShow.Structured.Scanning.csproj │ ├── EndpointDefinitionExtensions.cs │ ├── EndpointDefinitions/ │ │ ├── CustomerEndpointDefinition.cs │ │ ├── PaymentsEndpointDefinition.cs │ │ └── SwaggerEndpointDefinition.cs │ ├── IEndpointDefinition.cs │ ├── Models/ │ │ └── Customer.cs │ ├── Program.cs │ └── Services/ │ ├── CustomerService.cs │ └── ICustomerService.cs ├── DotnetDocsShow.Tests.Integration/ │ ├── BroadCustomerEndpointsTests.cs │ ├── DotnetDocsShow.Tests.Integration.csproj │ ├── NarrowCustomerEndpointsTests.cs │ └── TestApplicationFactory.cs ├── DotnetDocsShow.Tests.Unit/ │ ├── CustomerEndpointDefinitionTests.cs │ ├── DotnetDocsShow.Tests.Unit.csproj │ └── ResultExtensions.cs ├── DotnetDocsShow.Weather.MinimalApi/ │ ├── DotnetDocsShow.Weather.MinimalApi.csproj │ ├── Program.cs │ ├── WeatherEndpoints.cs │ ├── WeatherForecast.cs │ └── appsettings.json └── DotnetDocsShow.sln ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # DNX project.lock.json project.fragment.lock.json artifacts/ *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # TODO: Comment the next line if you want to checkin your web deploy settings # but database connection strings (with potential passwords) will be unencrypted #*.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # NuGet v3's project.json files produces more ignoreable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings node_modules/ orleans.codegen.cs # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files *.mdf *.ldf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # JetBrains Rider .idea/ *.sln.iml # CodeRush .cr/ # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc /obj/ ================================================ FILE: DotnetDocsShow.Extensions.Validation/Customers/Customer.cs ================================================ namespace DotnetDocsShow.Extensions.Validation.Customers; public class Customer { public Guid Id { get; } = Guid.NewGuid(); public string FullName { get; init; } = default!; } ================================================ FILE: DotnetDocsShow.Extensions.Validation/Customers/CustomerEndpoints.cs ================================================ using FluentValidation; namespace DotnetDocsShow.Extensions.Validation.Customers; public static class CustomerEndpoints { public static void MapCustomerEndpoints(this WebApplication app) { app.MapGet("/customers", GetAllCustomers); app.MapGet("/customers/{id}", GetCustomerById); app.MapPost("/customers", CreateCustomer).WithValidator(); app.MapPut("/customers/{id}", UpdateCustomer); app.MapDelete("/customers/{id}", DeleteCustomerById); } public static void AddCustomerServices(this IServiceCollection services) { services.AddSingleton(); } internal static List GetAllCustomers(ICustomerService service) { return service.GetAll(); } internal static IResult GetCustomerById(ICustomerService service, Guid id) { var customer = service.GetById(id); return customer is not null ? Results.Ok(customer) : Results.NotFound(); } internal static async Task CreateCustomerWithValidation( ICustomerService service, Customer customer, IValidator validator) { var validate = await validator.ValidateAsync(customer); if (!validate.IsValid) { return Results.BadRequest(validate.Errors); } service.Create(customer); return Results.Created($"/customers/{customer.Id}", customer); } internal static IResult CreateCustomer( ICustomerService service, Customer customer) { service.Create(customer); return Results.Created($"/customers/{customer.Id}", customer); } internal static IResult UpdateCustomer(ICustomerService service, Guid id, Customer updatedCustomer) { var customer = service.GetById(id); if (customer is null) { return Results.NotFound(); } service.Update(updatedCustomer); return Results.Ok(updatedCustomer); } internal static IResult DeleteCustomerById(ICustomerService service, Guid id) { service.Delete(id); return Results.Ok(); } } ================================================ FILE: DotnetDocsShow.Extensions.Validation/Customers/CustomerService.cs ================================================ namespace DotnetDocsShow.Extensions.Validation.Customers; public class CustomerService : ICustomerService { private readonly Dictionary _customers = new(); public void Create(Customer? customer) { if (customer is null) { return; } _customers[customer.Id] = customer; } public Customer? GetById(Guid id) { return _customers.GetValueOrDefault(id); } public List GetAll() { return _customers.Values.ToList(); } public void Update(Customer customer) { var existingCustomer = GetById(customer.Id); if (existingCustomer is null) { return; } _customers[customer.Id] = customer; } public void Delete(Guid id) { _customers.Remove(id); } } ================================================ FILE: DotnetDocsShow.Extensions.Validation/Customers/CustomerValidation.cs ================================================ using FluentValidation; namespace DotnetDocsShow.Extensions.Validation.Customers; public class CustomerValidation : AbstractValidator { public CustomerValidation() { RuleFor(x => x.Id).NotEmpty(); RuleFor(x => x.FullName).NotEmpty(); } } ================================================ FILE: DotnetDocsShow.Extensions.Validation/Customers/ICustomerService.cs ================================================ namespace DotnetDocsShow.Extensions.Validation.Customers; public interface ICustomerService { void Create(Customer? customer); Customer? GetById(Guid id); List GetAll(); void Update(Customer customer); void Delete(Guid id); } ================================================ FILE: DotnetDocsShow.Extensions.Validation/DotnetDocsShow.Extensions.Validation.csproj ================================================ Exe net6.0 enable enable ================================================ FILE: DotnetDocsShow.Extensions.Validation/IAssemblyMarker.cs ================================================ namespace DotnetDocsShow.Extensions.Validation; public interface IAssemblyMarker{} ================================================ FILE: DotnetDocsShow.Extensions.Validation/Program.cs ================================================ using DotnetDocsShow.Extensions.Validation; using DotnetDocsShow.Extensions.Validation.Customers; using FluentValidation; var builder = WebApplication.CreateBuilder(args); builder.Services.AddCustomerServices(); builder.Services.AddValidatorsFromAssemblyContaining(typeof(IAssemblyMarker)); var app = builder.Build(); app.MapCustomerEndpoints(); app.Run(); ================================================ FILE: DotnetDocsShow.Extensions.Validation/ValidationExtensions.cs ================================================ using FluentValidation; namespace DotnetDocsShow.Extensions.Validation; public static class ValidationExtensions { public static RouteHandlerBuilder WithValidator( this RouteHandlerBuilder builder) where TType : class { builder.Add(endpointBuilder => { var originalRequestDelegate = endpointBuilder.RequestDelegate; endpointBuilder.RequestDelegate = async context => { var validator = context.RequestServices.GetService>(); if (validator is null) { await originalRequestDelegate!(context); return; } context.Request.EnableBuffering(); var model = await context.Request.ReadFromJsonAsync(); if (model is null) { context.Response.StatusCode = 400; await context.Response.WriteAsJsonAsync(new { error = "Couldn't map the model from the request body" }); return; } var result = await validator.ValidateAsync(model); if (!result.IsValid) { context.Response.StatusCode = 400; await context.Response.WriteAsJsonAsync(new { errors = result.Errors }); return; } context.Request.Body.Position = 0; await originalRequestDelegate!(context); }; }); return builder; } } ================================================ FILE: DotnetDocsShow.Intro.MinimalApi/DotnetDocsShow.Intro.MinimalApi.csproj ================================================ Exe net6.0 enable enable ================================================ FILE: DotnetDocsShow.Intro.MinimalApi/Program.cs ================================================ var app = WebApplication.Create(); app.MapGet("helloworld", () => "Hello world!"); app.Run(); ================================================ FILE: DotnetDocsShow.MinimalApiTests.Structured/DotnetDocsShow.MinimalApiTests.Structured.csproj ================================================ Exe net6.0 enable enable ================================================ FILE: DotnetDocsShow.MinimalApiTests.Structured/EndpointDefinitionExtensions.cs ================================================ namespace DotnetDocsShow.MinimalApiTests.Structured; public static class EndpointDefinitionExtensions { public static void AddEndpointDefinitions( this IServiceCollection services, params Type[] scanMarkers) { var endpointDefinitions = new List(); foreach (var marker in scanMarkers) { endpointDefinitions.AddRange( marker.Assembly.ExportedTypes .Where(x => typeof(IEndpointDefinition).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract) .Select(Activator.CreateInstance).Cast() ); } foreach (var endpointDefinition in endpointDefinitions) { endpointDefinition.DefineServices(services); } services.AddSingleton(endpointDefinitions as IReadOnlyCollection); } public static void UseEndpointDefinitions(this WebApplication app) { var definitions = app.Services.GetRequiredService>(); foreach (var endpointDefinition in definitions) { endpointDefinition.DefineEndpoints(app); } } } ================================================ FILE: DotnetDocsShow.MinimalApiTests.Structured/EndpointDefinitions/CustomerEndpointDefinition.cs ================================================ using DotnetDocsShow.MinimalApiTests.Structured.Models; using DotnetDocsShow.MinimalApiTests.Structured.Services; namespace DotnetDocsShow.MinimalApiTests.Structured.EndpointDefinitions; public class CustomerEndpointDefinition : IEndpointDefinition { public void DefineEndpoints(WebApplication app) { app.MapGet("/customers", GetAllCustomers); app.MapGet("/customers/{id}", GetCustomerById); app.MapPost("/customers", CreateCustomer); app.MapPut("/customers/{id}", UpdateCustomer); app.MapDelete("/customers/{id}", DeleteCustomerById); } internal List GetAllCustomers(ICustomerService service) { return service.GetAll(); } internal IResult GetCustomerById(ICustomerService service, Guid id) { var customer = service.GetById(id); return customer is not null ? Results.Ok(customer) : Results.NotFound(); } internal IResult CreateCustomer(ICustomerService service, Customer customer) { service.Create(customer); return Results.Created($"/customers/{customer.Id}", customer); } internal IResult UpdateCustomer(ICustomerService service, Guid id, Customer updatedCustomer) { var customer = service.GetById(id); if (customer is null) { return Results.NotFound(); } service.Update(updatedCustomer); return Results.Ok(updatedCustomer); } internal IResult DeleteCustomerById(ICustomerService service, Guid id) { service.Delete(id); return Results.Ok(); } public void DefineServices(IServiceCollection services) { services.AddSingleton(); } } ================================================ FILE: DotnetDocsShow.MinimalApiTests.Structured/EndpointDefinitions/SwaggerEndpointDefinition.cs ================================================ using Microsoft.OpenApi.Models; namespace DotnetDocsShow.MinimalApiTests.Structured.EndpointDefinitions; public class SwaggerEndpointDefinition : IEndpointDefinition { public void DefineEndpoints(WebApplication app) { app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "DotnetDocsShow.MinimalApiTests.Structured v1")); } public void DefineServices(IServiceCollection services) { services.AddEndpointsApiExplorer(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "DotnetDocsShow.MinimalApiTests.Structured", Version = "v1" }); }); } } ================================================ FILE: DotnetDocsShow.MinimalApiTests.Structured/IEndpointDefinition.cs ================================================ namespace DotnetDocsShow.MinimalApiTests.Structured; public interface IEndpointDefinition { void DefineServices(IServiceCollection services); void DefineEndpoints(WebApplication app); } ================================================ FILE: DotnetDocsShow.MinimalApiTests.Structured/Models/Customer.cs ================================================ using System.Text.Json.Serialization; namespace DotnetDocsShow.MinimalApiTests.Structured.Models; public class Customer { [JsonPropertyName("id")] public Guid Id { get; init; } = Guid.NewGuid(); [JsonPropertyName("fullName")] public string FullName { get; init; } = default!; } ================================================ FILE: DotnetDocsShow.MinimalApiTests.Structured/Program.cs ================================================ using DotnetDocsShow.MinimalApiTests.Structured; var builder = WebApplication.CreateBuilder(args); builder.Services.AddEndpointDefinitions(typeof(IEndpointDefinition)); var app = builder.Build(); app.UseEndpointDefinitions(); app.Run(); ================================================ FILE: DotnetDocsShow.MinimalApiTests.Structured/Services/CustomerService.cs ================================================ using DotnetDocsShow.MinimalApiTests.Structured.Models; namespace DotnetDocsShow.MinimalApiTests.Structured.Services; public class CustomerService : ICustomerService { private readonly Dictionary _customers = new(); public void Create(Customer? customer) { if (customer is null) { return; } _customers[customer.Id] = customer; } public Customer? GetById(Guid id) { return _customers.GetValueOrDefault(id); } public List GetAll() { return _customers.Values.ToList(); } public void Update(Customer customer) { var existingCustomer = GetById(customer.Id); if (existingCustomer is null) { return; } _customers[customer.Id] = customer; } public void Delete(Guid id) { _customers.Remove(id); } } ================================================ FILE: DotnetDocsShow.MinimalApiTests.Structured/Services/ICustomerService.cs ================================================ using DotnetDocsShow.MinimalApiTests.Structured.Models; namespace DotnetDocsShow.MinimalApiTests.Structured.Services; public interface ICustomerService { void Create(Customer? customer); Customer? GetById(Guid id); List GetAll(); void Update(Customer customer); void Delete(Guid id); } ================================================ FILE: DotnetDocsShow.NewWebApi/Controllers/WeatherForecastController.cs ================================================ using Microsoft.AspNetCore.Mvc; namespace DotnetDocsShow.NewWebApi.Controllers; [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private static readonly Random Random = new(489); private static readonly string[] Summaries = { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; [HttpGet(Name = "GetWeatherForecast")] public IEnumerable Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Next(-20, 55), Summary = Summaries[Random.Next(Summaries.Length)] }) .ToArray(); } } ================================================ FILE: DotnetDocsShow.NewWebApi/DotnetDocsShow.NewWebApi.csproj ================================================ net6.0 enable enable ================================================ FILE: DotnetDocsShow.NewWebApi/Program.cs ================================================ var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); ================================================ FILE: DotnetDocsShow.NewWebApi/Properties/launchSettings.json ================================================ { "$schema": "https://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:56176", "sslPort": 44384 } }, "profiles": { "DotnetDocsShow.NewWebApi": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, "launchUrl": "swagger", "applicationUrl": "https://localhost:7256;http://localhost:5256", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } ================================================ FILE: DotnetDocsShow.NewWebApi/WeatherForecast.cs ================================================ namespace DotnetDocsShow.NewWebApi; public class WeatherForecast { public DateTime Date { get; set; } public int TemperatureC { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); public string? Summary { get; set; } } ================================================ FILE: DotnetDocsShow.NewWebApi/appsettings.Development.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } } } ================================================ FILE: DotnetDocsShow.NewWebApi/appsettings.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" } ================================================ FILE: DotnetDocsShow.OldWebApi/Controllers/WeatherForecastController.cs ================================================ using Microsoft.AspNetCore.Mvc; namespace DotnetDocsShow.OldWebApi.Controllers; [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private static readonly Random Random = new(489); private static readonly string[] Summaries = { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; [HttpGet] public IEnumerable Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Next(-20, 55), Summary = Summaries[Random.Next(Summaries.Length)] }) .ToArray(); } } ================================================ FILE: DotnetDocsShow.OldWebApi/DotnetDocsShow.OldWebApi.csproj ================================================ net6.0 enable ================================================ FILE: DotnetDocsShow.OldWebApi/Program.cs ================================================ namespace DotnetDocsShow.OldWebApi; public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); } ================================================ FILE: DotnetDocsShow.OldWebApi/Properties/launchSettings.json ================================================ { "$schema": "http://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:17516", "sslPort": 44325 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "DotnetDocsShow.OldWebApi": { "commandName": "Project", "dotnetRunMessages": "true", "launchBrowser": false, "launchUrl": "swagger", "applicationUrl": "https://localhost:5001;http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } ================================================ FILE: DotnetDocsShow.OldWebApi/Startup.cs ================================================ using Microsoft.OpenApi.Models; namespace DotnetDocsShow.OldWebApi; public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "DotnetDocsShow.OldWebApi", Version = "v1" }); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "DotnetDocsShow.OldWebApi v1")); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } ================================================ FILE: DotnetDocsShow.OldWebApi/WeatherForecast.cs ================================================ namespace DotnetDocsShow.OldWebApi; public class WeatherForecast { public DateTime Date { get; set; } public int TemperatureC { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); public string Summary { get; set; } } ================================================ FILE: DotnetDocsShow.OldWebApi/appsettings.Development.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } } } ================================================ FILE: DotnetDocsShow.OldWebApi/appsettings.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" } ================================================ FILE: DotnetDocsShow.PerformanceTests/DotnetDocsShow.PerformanceTests.csproj ================================================ Exe net6.0 enable enable ================================================ FILE: DotnetDocsShow.PerformanceTests/Program.cs ================================================ using NBomber.Contracts; using NBomber.CSharp; using NBomber.Plugins.Http.CSharp; var httpFactory = HttpClientFactory.Create(); var oldWebApiStep = CreateStep("old_web_api_step", httpFactory, "https://localhost:5001/weatherforecast"); var newWebApiStep = CreateStep("new_web_api_step", httpFactory, "https://localhost:7256/weatherforecast"); var minimalApiStep = CreateStep("minimal_api_step", httpFactory, "https://localhost:1337/weatherforecast"); var oldWebApiScenario = CreateScenario("old_web_api", oldWebApiStep, 10, TimeSpan.FromSeconds(60)); var newWebApiScenario = CreateScenario("new_web_api", newWebApiStep, 10, TimeSpan.FromSeconds(60)); var minimalApiScenario = CreateScenario("minimal_api", minimalApiStep, 10, TimeSpan.FromSeconds(60)); NBomberRunner .RegisterScenarios(oldWebApiScenario, newWebApiScenario, minimalApiScenario) .Run(); IStep CreateStep(string stepName, IClientFactory httpClientFactory, string endpoint) => Step.Create(stepName, httpClientFactory, async context => { var response = await context.Client.GetAsync(endpoint, context.CancellationToken); return response.IsSuccessStatusCode ? Response.Ok(statusCode: (int)response.StatusCode) : Response.Fail(statusCode: (int)response.StatusCode); }); Scenario CreateScenario(string scenarioName, IStep step, int copies, TimeSpan duration) => ScenarioBuilder .CreateScenario(scenarioName, step) .WithWarmUpDuration(TimeSpan.FromSeconds(5)) .WithLoadSimulations(Simulation.KeepConstant(copies, duration)); ================================================ FILE: DotnetDocsShow.Structured.Extensions/Customers/Customer.cs ================================================ namespace DotnetDocsShow.Structured.Extensions.Customers; public class Customer { public Guid Id { get; } = Guid.NewGuid(); public string FullName { get; init; } = default!; } ================================================ FILE: DotnetDocsShow.Structured.Extensions/Customers/CustomerEndpoints.cs ================================================ namespace DotnetDocsShow.Structured.Extensions.Customers; public static class CustomerEndpoints { public static void MapCustomerEndpoints(this WebApplication app) { app.MapGet("/customers", GetAllCustomers); app.MapGet("/customers/{id}", GetCustomerById); app.MapPost("/customers", CreateCustomer); app.MapPut("/customers/{id}", UpdateCustomer); app.MapDelete("/customers/{id}", DeleteCustomerById); } public static void AddCustomerServices(this IServiceCollection services) { services.AddSingleton(); } internal static List GetAllCustomers(ICustomerService service) { return service.GetAll(); } internal static IResult GetCustomerById(ICustomerService service, Guid id) { var customer = service.GetById(id); return customer is not null ? Results.Ok(customer) : Results.NotFound(); } internal static IResult CreateCustomer(ICustomerService service, Customer customer) { service.Create(customer); return Results.Created($"/customers/{customer.Id}", customer); } internal static IResult UpdateCustomer(ICustomerService service, Guid id, Customer updatedCustomer) { var customer = service.GetById(id); if (customer is null) { return Results.NotFound(); } service.Update(updatedCustomer); return Results.Ok(updatedCustomer); } internal static IResult DeleteCustomerById(ICustomerService service, Guid id) { service.Delete(id); return Results.Ok(); } } ================================================ FILE: DotnetDocsShow.Structured.Extensions/Customers/CustomerService.cs ================================================ namespace DotnetDocsShow.Structured.Extensions.Customers; public class CustomerService : ICustomerService { private readonly Dictionary _customers = new(); public void Create(Customer? customer) { if (customer is null) { return; } _customers[customer.Id] = customer; } public Customer? GetById(Guid id) { return _customers.GetValueOrDefault(id); } public List GetAll() { return _customers.Values.ToList(); } public void Update(Customer customer) { var existingCustomer = GetById(customer.Id); if (existingCustomer is null) { return; } _customers[customer.Id] = customer; } public void Delete(Guid id) { _customers.Remove(id); } } ================================================ FILE: DotnetDocsShow.Structured.Extensions/Customers/ICustomerService.cs ================================================ namespace DotnetDocsShow.Structured.Extensions.Customers; public interface ICustomerService { void Create(Customer? customer); Customer? GetById(Guid id); List GetAll(); void Update(Customer customer); void Delete(Guid id); } ================================================ FILE: DotnetDocsShow.Structured.Extensions/DotnetDocsShow.Structured.Extensions.csproj ================================================ Exe net6.0 enable enable ================================================ FILE: DotnetDocsShow.Structured.Extensions/Program.cs ================================================ using DotnetDocsShow.Structured.Extensions.Customers; var builder = WebApplication.CreateBuilder(args); builder.Services.AddCustomerServices(); var app = builder.Build(); app.MapCustomerEndpoints(); app.Run(); ================================================ FILE: DotnetDocsShow.Structured.Mediator/DotnetDocsShow.Structured.Mediator.csproj ================================================ Exe net6.0 enable enable ================================================ FILE: DotnetDocsShow.Structured.Mediator/Handlers/CreateCustomerRequestHandler.cs ================================================ using System.Text.Json.Serialization; using DotnetDocsShow.Structured.Mediator.Models; using DotnetDocsShow.Structured.Mediator.Services; using MediatR; namespace DotnetDocsShow.Structured.Mediator.Handlers; public record CreateCustomerRequest : IRequest { [JsonPropertyName("id")] public Guid Id { get; init; } = Guid.NewGuid(); [JsonPropertyName("fullName")] public string FullName { get; init; } = default!; } public class CreateCustomerRequestHandler : IRequestHandler { private readonly ICustomerService _customerService; public CreateCustomerRequestHandler(ICustomerService customerService) { _customerService = customerService; } public Task Handle(CreateCustomerRequest request, CancellationToken cancellationToken) { var customer = new Customer { FullName = request.FullName, Id = request.Id }; _customerService.Create(customer); var response = Results.Created($"/customers/{customer.Id}", customer); return Task.FromResult(response); } } ================================================ FILE: DotnetDocsShow.Structured.Mediator/Handlers/DeleteCustomerByIdRequestHandler.cs ================================================ using System.Text.Json.Serialization; using DotnetDocsShow.Structured.Mediator.Services; using MediatR; namespace DotnetDocsShow.Structured.Mediator.Handlers; public record DeleteCustomerByIdRequest : IRequest { [JsonPropertyName("id")] public Guid Id { get; init; } public DeleteCustomerByIdRequest(Guid id) { Id = id; } } public class DeleteCustomerByIdRequestHandler : IRequestHandler { private readonly ICustomerService _customerService; public DeleteCustomerByIdRequestHandler(ICustomerService customerService) { _customerService = customerService; } public Task Handle(DeleteCustomerByIdRequest request, CancellationToken cancellationToken) { _customerService.Delete(request.Id); return Task.FromResult(Results.Ok()); } } ================================================ FILE: DotnetDocsShow.Structured.Mediator/Handlers/GetAllCustomersRequestHandler.cs ================================================ using DotnetDocsShow.Structured.Mediator.Services; using MediatR; namespace DotnetDocsShow.Structured.Mediator.Handlers; public record GetAllCustomersRequest : IRequest; public class GetAllCustomersRequestHandler : IRequestHandler { private readonly ICustomerService _customerService; public GetAllCustomersRequestHandler(ICustomerService customerService) { _customerService = customerService; } public Task Handle( GetAllCustomersRequest request, CancellationToken cancellationToken) { var customers = _customerService.GetAll(); var response = Results.Ok(customers); return Task.FromResult(response); } } ================================================ FILE: DotnetDocsShow.Structured.Mediator/Handlers/GetCustomerByIdRequestHandler.cs ================================================ using System.Text.Json.Serialization; using DotnetDocsShow.Structured.Mediator.Services; using MediatR; namespace DotnetDocsShow.Structured.Mediator.Handlers; public record GetCustomerByIdRequest : IRequest { [JsonPropertyName("id")] public Guid Id { get; init; } public GetCustomerByIdRequest(Guid id) { Id = id; } } public class GetCustomerByIdRequestHandler : IRequestHandler { private readonly ICustomerService _customerService; public GetCustomerByIdRequestHandler(ICustomerService customerService) { _customerService = customerService; } public Task Handle(GetCustomerByIdRequest request, CancellationToken cancellationToken) { var customer = _customerService.GetById(request.Id); var response = customer is not null ? Results.Ok(customer) : Results.NotFound(); return Task.FromResult(response); } } ================================================ FILE: DotnetDocsShow.Structured.Mediator/Models/Customer.cs ================================================ namespace DotnetDocsShow.Structured.Mediator.Models; public class Customer { public Guid Id { get; init; } = Guid.NewGuid(); public string FullName { get; init; } = default!; } ================================================ FILE: DotnetDocsShow.Structured.Mediator/Program.cs ================================================ using DotnetDocsShow.Structured.Mediator; using DotnetDocsShow.Structured.Mediator.Handlers; using DotnetDocsShow.Structured.Mediator.Models; using DotnetDocsShow.Structured.Mediator.Services; using MediatR; var builder = WebApplication.CreateBuilder(); builder.Services.AddSingleton(); builder.Services.AddMediatR(typeof(Customer)); var app = builder.Build(); app.MapGet("customers", async (IMediator mediator) => await mediator.Send(new GetAllCustomersRequest())); app.MapGet("/customers/{id}", async (IMediator mediator, Guid id) => await mediator.Send(new GetCustomerByIdRequest(id))); app.MapPost("/customers", async (IMediator mediator, CreateCustomerRequest request) => await mediator.Send(request)); app.MapDelete("/customers/{id}", async (IMediator mediator, Guid id) => await mediator.Send(new DeleteCustomerByIdRequest(id))); app.Run(); ================================================ FILE: DotnetDocsShow.Structured.Mediator/Services/CustomerService.cs ================================================ using DotnetDocsShow.Structured.Mediator.Models; namespace DotnetDocsShow.Structured.Mediator.Services; public class CustomerService : ICustomerService { private readonly Dictionary _customers = new(); public void Create(Customer? customer) { if (customer is null) { return; } _customers[customer.Id] = customer; } public Customer? GetById(Guid id) { return _customers.GetValueOrDefault(id); } public List GetAll() { return _customers.Values.ToList(); } public void Update(Customer customer) { var existingCustomer = GetById(customer.Id); if (existingCustomer is null) { return; } _customers[customer.Id] = customer; } public void Delete(Guid id) { _customers.Remove(id); } } ================================================ FILE: DotnetDocsShow.Structured.Mediator/Services/ICustomerService.cs ================================================ using DotnetDocsShow.Structured.Mediator.Models; namespace DotnetDocsShow.Structured.Mediator.Services; public interface ICustomerService { void Create(Customer? customer); Customer? GetById(Guid id); List GetAll(); void Update(Customer customer); void Delete(Guid id); } ================================================ FILE: DotnetDocsShow.Structured.Scanning/DotnetDocsShow.Structured.Scanning.csproj ================================================ Exe net6.0 enable enable ================================================ FILE: DotnetDocsShow.Structured.Scanning/EndpointDefinitionExtensions.cs ================================================ namespace DotnetDocsShow.Structured.Scanning; public static class EndpointDefinitionExtensions { public static void AddEndpointDefinitions( this IServiceCollection services, params Type[] scanMarkers) { var endpointDefinitions = new List(); foreach (var marker in scanMarkers) { endpointDefinitions.AddRange( marker.Assembly.ExportedTypes .Where(x => typeof(IEndpointDefinition).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract) .Select(Activator.CreateInstance).Cast() ); } foreach (var endpointDefinition in endpointDefinitions) { endpointDefinition.DefineServices(services); } services.AddSingleton(endpointDefinitions as IReadOnlyCollection); } public static void UseEndpointDefinitions(this WebApplication app) { var definitions = app.Services.GetRequiredService>(); foreach (var endpointDefinition in definitions) { endpointDefinition.DefineEndpoints(app); } } } ================================================ FILE: DotnetDocsShow.Structured.Scanning/EndpointDefinitions/CustomerEndpointDefinition.cs ================================================ using DotnetDocsShow.Structured.Scanning.Models; using DotnetDocsShow.Structured.Scanning.Services; namespace DotnetDocsShow.Structured.Scanning.EndpointDefinitions; public class CustomerEndpointDefinition : IEndpointDefinition { public void DefineEndpoints(WebApplication app) { app.MapGet("/customers", GetAllCustomers); app.MapGet("/customers/{id}", GetCustomerById); app.MapPost("/customers", CreateCustomer); app.MapPut("/customers/{id}", UpdateCustomer); app.MapDelete("/customers/{id}", DeleteCustomerById); } internal List GetAllCustomers(ICustomerService service) { return service.GetAll(); } internal IResult GetCustomerById(ICustomerService service, Guid id) { var customer = service.GetById(id); return customer is not null ? Results.Ok(customer) : Results.NotFound(); } internal IResult CreateCustomer(ICustomerService service, Customer customer) { service.Create(customer); return Results.Created($"/customers/{customer.Id}", customer); } internal IResult UpdateCustomer(ICustomerService service, Guid id, Customer updatedCustomer) { var customer = service.GetById(id); if (customer is null) { return Results.NotFound(); } service.Update(updatedCustomer); return Results.Ok(updatedCustomer); } internal IResult DeleteCustomerById(ICustomerService service, Guid id) { service.Delete(id); return Results.Ok(); } public void DefineServices(IServiceCollection services) { services.AddSingleton(); } } ================================================ FILE: DotnetDocsShow.Structured.Scanning/EndpointDefinitions/PaymentsEndpointDefinition.cs ================================================ namespace DotnetDocsShow.Structured.Scanning.EndpointDefinitions; public class PaymentsEndpointDefinition : IEndpointDefinition { public void DefineServices(IServiceCollection services) { } public void DefineEndpoints(WebApplication app) { } } ================================================ FILE: DotnetDocsShow.Structured.Scanning/EndpointDefinitions/SwaggerEndpointDefinition.cs ================================================ using Microsoft.OpenApi.Models; namespace DotnetDocsShow.Structured.Scanning.EndpointDefinitions; public class SwaggerEndpointDefinition : IEndpointDefinition { public void DefineEndpoints(WebApplication app) { app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "DotnetDocsShow.Structured.Custom v1")); } public void DefineServices(IServiceCollection services) { services.AddEndpointsApiExplorer(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "DotnetDocsShow.Structured.Custom", Version = "v1" }); }); } } ================================================ FILE: DotnetDocsShow.Structured.Scanning/IEndpointDefinition.cs ================================================ namespace DotnetDocsShow.Structured.Scanning; public interface IEndpointDefinition { void DefineServices(IServiceCollection services); void DefineEndpoints(WebApplication app); } ================================================ FILE: DotnetDocsShow.Structured.Scanning/Models/Customer.cs ================================================ namespace DotnetDocsShow.Structured.Scanning.Models; public class Customer { public Guid Id { get; init; } = Guid.NewGuid(); public string FullName { get; init; } = default!; } ================================================ FILE: DotnetDocsShow.Structured.Scanning/Program.cs ================================================ using DotnetDocsShow.Structured.Scanning; var builder = WebApplication.CreateBuilder(args); builder.Services.AddEndpointDefinitions(typeof(IEndpointDefinition)); var app = builder.Build(); app.UseEndpointDefinitions(); app.Run(); ================================================ FILE: DotnetDocsShow.Structured.Scanning/Services/CustomerService.cs ================================================ using DotnetDocsShow.Structured.Scanning.Models; namespace DotnetDocsShow.Structured.Scanning.Services; public class CustomerService : ICustomerService { private readonly Dictionary _customers = new(); public void Create(Customer? customer) { if (customer is null) { return; } _customers[customer.Id] = customer; } public Customer? GetById(Guid id) { return _customers.GetValueOrDefault(id); } public List GetAll() { return _customers.Values.ToList(); } public void Update(Customer customer) { var existingCustomer = GetById(customer.Id); if (existingCustomer is null) { return; } _customers[customer.Id] = customer; } public void Delete(Guid id) { _customers.Remove(id); } } ================================================ FILE: DotnetDocsShow.Structured.Scanning/Services/ICustomerService.cs ================================================ using DotnetDocsShow.Structured.Scanning.Models; namespace DotnetDocsShow.Structured.Scanning.Services; public interface ICustomerService { void Create(Customer? customer); Customer? GetById(Guid id); List GetAll(); void Update(Customer customer); void Delete(Guid id); } ================================================ FILE: DotnetDocsShow.Tests.Integration/BroadCustomerEndpointsTests.cs ================================================ using System; using System.Net; using System.Net.Http.Json; using System.Text.Json; using System.Threading.Tasks; using DotnetDocsShow.MinimalApiTests.Structured.Models; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using NSubstitute; using Xunit; namespace DotnetDocsShow.Tests.Integration; public class BroadCustomerEndpointsTests { [Fact] public async Task GetCustomerById_ReturnCustomer_WhenCustomerExists() { //Arrange var id = Guid.NewGuid(); var customer = new Customer{ Id = id, FullName = "Nick Chapsas"}; using var app = new TestApplicationFactory(); var httpClient = app.CreateClient(); await httpClient.PostAsJsonAsync("/customers", customer); //Act var response = await httpClient.GetAsync($"/customers/{id}"); var responseText = await response.Content.ReadAsStringAsync(); var customerResult = JsonSerializer.Deserialize(responseText); //Assert response.StatusCode.Should().Be(HttpStatusCode.OK); customerResult.Should().BeEquivalentTo(customer); } [Fact] public async Task GetCustomerById_ReturnNotFound_WhenCustomerDoesNotExists() { //Arrange using var app = new TestApplicationFactory(); var guid = Guid.NewGuid(); var httpClient = app.CreateClient(); //Act var response = await httpClient.GetAsync($"/customers/{guid}"); //Assert response.StatusCode.Should().Be(HttpStatusCode.NotFound); } } ================================================ FILE: DotnetDocsShow.Tests.Integration/DotnetDocsShow.Tests.Integration.csproj ================================================ net6.0 enable false runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive all ================================================ FILE: DotnetDocsShow.Tests.Integration/NarrowCustomerEndpointsTests.cs ================================================ using System; using System.Net; using System.Text.Json; using System.Threading.Tasks; using DotnetDocsShow.MinimalApiTests.Structured.Models; using DotnetDocsShow.MinimalApiTests.Structured.Services; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using NSubstitute; using Xunit; namespace DotnetDocsShow.Tests.Integration; public class NarrowCustomerEndpointsTests { private readonly ICustomerService _customerService = Substitute.For(); [Fact] public async Task GetCustomerById_ReturnCustomer_WhenCustomerExists() { //Arrange var id = Guid.NewGuid(); var customer = new Customer{ Id = id, FullName = "Nick Chapsas"}; _customerService.GetById(Arg.Is(id)).Returns(customer); using var app = new TestApplicationFactory(x => { x.AddSingleton(_customerService); }); var httpClient = app.CreateClient(); //Act var response = await httpClient.GetAsync($"/customers/{id}"); var responseText = await response.Content.ReadAsStringAsync(); var customerResult = JsonSerializer.Deserialize(responseText); //Assert response.StatusCode.Should().Be(HttpStatusCode.OK); customerResult.Should().BeEquivalentTo(customer); } [Fact] public async Task GetCustomerById_ReturnNotFound_WhenCustomerDoesNotExists() { //Arrange _customerService.GetById(Arg.Any()).Returns((Customer?)null); using var app = new TestApplicationFactory(x => { x.AddSingleton(_customerService); }); var guid = Guid.NewGuid(); var httpClient = app.CreateClient(); //Act var response = await httpClient.GetAsync($"/customers/{guid}"); //Assert response.StatusCode.Should().Be(HttpStatusCode.NotFound); } } ================================================ FILE: DotnetDocsShow.Tests.Integration/TestApplicationFactory.cs ================================================ using System; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace DotnetDocsShow.Tests.Integration; internal class TestApplicationFactory : WebApplicationFactory { private readonly Action? _serviceOverride; public TestApplicationFactory(Action? serviceOverride = null) { _serviceOverride = serviceOverride; } protected override IHost CreateHost(IHostBuilder builder) { if (_serviceOverride is not null) { builder.ConfigureServices(_serviceOverride); } return base.CreateHost(builder); } } ================================================ FILE: DotnetDocsShow.Tests.Unit/CustomerEndpointDefinitionTests.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using DotnetDocsShow.MinimalApiTests.Structured.EndpointDefinitions; using DotnetDocsShow.MinimalApiTests.Structured.Models; using DotnetDocsShow.MinimalApiTests.Structured.Services; using FluentAssertions; using NSubstitute; using Xunit; namespace DotnetDocsShow.Tests.Unit; public class CustomerEndpointDefinitionTests { private readonly ICustomerService _customerService = Substitute.For(); private readonly CustomerEndpointDefinition _sut = new(); [Fact] public void GetAllCustomers_ReturnEmptyList_WhenNoCustomersExist() { //Arrange _customerService.GetAll().Returns(new List()); //Act var result = _sut.GetAllCustomers(_customerService); //Assert result.Should().BeEmpty(); } [Fact] public void GetAllCustomers_ReturnsCustomer_WhenCustomerExists() { //Arrange var id = Guid.NewGuid(); var customer = new Customer { Id = id, FullName = "Nick Chapsas" }; _customerService.GetAll().Returns(new List { customer }); //Act var result = _sut.GetAllCustomers(_customerService); //Assert result.Should().ContainSingle(x => x.Id == id && x.FullName == "Nick Chapsas"); } } ================================================ FILE: DotnetDocsShow.Tests.Unit/DotnetDocsShow.Tests.Unit.csproj ================================================ net6.0 enable false runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive all ================================================ FILE: DotnetDocsShow.Tests.Unit/ResultExtensions.cs ================================================ using System; using Microsoft.AspNetCore.Http; namespace DotnetDocsShow.Tests.Unit; public static class ResultExtensions { public static T? GetOkObjectResultValue(this IResult result) { return (T?)Type.GetType("Microsoft.AspNetCore.Http.Result.OkObjectResult, Microsoft.AspNetCore.Http.Results")? .GetProperty("Value", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public)? .GetValue(result); } public static int? GetOkObjectResultStatusCode(this IResult result) { return (int?)Type.GetType("Microsoft.AspNetCore.Http.Result.OkObjectResult, Microsoft.AspNetCore.Http.Results")? .GetProperty("StatusCode", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public)? .GetValue(result); } public static int? GetNotFoundResultStatusCode(this IResult result) { return (int?)Type.GetType("Microsoft.AspNetCore.Http.Result.NotFoundObjectResult, Microsoft.AspNetCore.Http.Results")? .GetProperty("StatusCode", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public)? .GetValue(result); } } ================================================ FILE: DotnetDocsShow.Weather.MinimalApi/DotnetDocsShow.Weather.MinimalApi.csproj ================================================ Exe net6.0 enable enable ================================================ FILE: DotnetDocsShow.Weather.MinimalApi/Program.cs ================================================ using DotnetDocsShow.Weather.MinimalApi; 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.AddAuthorization(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapWeatherEndpoints(); app.Run("https://localhost:1337"); ================================================ FILE: DotnetDocsShow.Weather.MinimalApi/WeatherEndpoints.cs ================================================ namespace DotnetDocsShow.Weather.MinimalApi; public static class WeatherEndpoints { private static Random Random = new(489); private static string[] Summaries = { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; public static void MapWeatherEndpoints(this WebApplication app) { app.MapGet("weatherforecast", () => { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Next(-20, 55), Summary = Summaries[Random.Next(Summaries.Length)] }) .ToArray(); }) .Produces(200, typeof(IEnumerable)) .AllowAnonymous(); } } ================================================ FILE: DotnetDocsShow.Weather.MinimalApi/WeatherForecast.cs ================================================ namespace DotnetDocsShow.Weather.MinimalApi; public class WeatherForecast { public DateTime Date { get; set; } public int TemperatureC { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); public string? Summary { get; set; } } ================================================ FILE: DotnetDocsShow.Weather.MinimalApi/appsettings.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" } ================================================ FILE: DotnetDocsShow.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1. Comparision", "1. Comparision", "{6FB66046-57C1-4669-84E1-0905DADC000E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4. Structuring", "4. Structuring", "{8618805B-A0E5-4B0A-B52D-FF5429D814E2}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "5. Testing", "5. Testing", "{1E5E6DC2-39AE-4B52-83A7-46B28FEF72C3}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2. Performance", "2. Performance", "{A18A5368-4F83-428C-ABA5-838FE467A581}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.NewWebApi", "DotnetDocsShow.NewWebApi\DotnetDocsShow.NewWebApi.csproj", "{6CA5CC96-0678-4723-B5B3-E2464516C277}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.PerformanceTests", "DotnetDocsShow.PerformanceTests\DotnetDocsShow.PerformanceTests.csproj", "{71788840-6B85-42A5-9D52-D51A802A21BE}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.OldWebApi", "DotnetDocsShow.OldWebApi\DotnetDocsShow.OldWebApi.csproj", "{5EB40414-02BE-44A5-A14C-E619914A0F4A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.Weather.MinimalApi", "DotnetDocsShow.Weather.MinimalApi\DotnetDocsShow.Weather.MinimalApi.csproj", "{AD793B6C-DF05-458E-854B-ECFCAF7167AD}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.Tests.Unit", "DotnetDocsShow.Tests.Unit\DotnetDocsShow.Tests.Unit.csproj", "{96598D5F-199D-45E7-9F80-98FD10DCD24A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.Tests.Integration", "DotnetDocsShow.Tests.Integration\DotnetDocsShow.Tests.Integration.csproj", "{0D8831BD-6C91-49ED-9BE7-AEA7A6DA821F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.MinimalApiTests.Structured", "DotnetDocsShow.MinimalApiTests.Structured\DotnetDocsShow.MinimalApiTests.Structured.csproj", "{E6AFFD49-C560-4947-8076-48E3F87AACAC}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.Structured.Scanning", "DotnetDocsShow.Structured.Scanning\DotnetDocsShow.Structured.Scanning.csproj", "{D7F4582E-2A51-4BCA-A4D6-A11B92EDAA2F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.Structured.Extensions", "DotnetDocsShow.Structured.Extensions\DotnetDocsShow.Structured.Extensions.csproj", "{020FC895-5E41-41A6-9C10-E2BCEBE40842}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.Structured.Mediator", "DotnetDocsShow.Structured.Mediator\DotnetDocsShow.Structured.Mediator.csproj", "{DCFF64BC-6B91-4121-BB4B-0A34AD3A6C84}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "0. Intro", "0. Intro", "{8975828E-1794-41B6-8F82-41F70F52C270}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3. Extensions", "3. Extensions", "{6BD6DACA-80E0-4683-A6B3-649D79F8994C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.Extensions.Validation", "DotnetDocsShow.Extensions.Validation\DotnetDocsShow.Extensions.Validation.csproj", "{12E1D11E-6E0E-4F40-91BB-996E71CC15C3}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDocsShow.Intro.MinimalApi", "DotnetDocsShow.Intro.MinimalApi\DotnetDocsShow.Intro.MinimalApi.csproj", "{A3ECA132-FE31-46DF-8715-285B41409A1D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {6CA5CC96-0678-4723-B5B3-E2464516C277} = {6FB66046-57C1-4669-84E1-0905DADC000E} {71788840-6B85-42A5-9D52-D51A802A21BE} = {A18A5368-4F83-428C-ABA5-838FE467A581} {5EB40414-02BE-44A5-A14C-E619914A0F4A} = {6FB66046-57C1-4669-84E1-0905DADC000E} {AD793B6C-DF05-458E-854B-ECFCAF7167AD} = {6FB66046-57C1-4669-84E1-0905DADC000E} {96598D5F-199D-45E7-9F80-98FD10DCD24A} = {1E5E6DC2-39AE-4B52-83A7-46B28FEF72C3} {0D8831BD-6C91-49ED-9BE7-AEA7A6DA821F} = {1E5E6DC2-39AE-4B52-83A7-46B28FEF72C3} {E6AFFD49-C560-4947-8076-48E3F87AACAC} = {1E5E6DC2-39AE-4B52-83A7-46B28FEF72C3} {D7F4582E-2A51-4BCA-A4D6-A11B92EDAA2F} = {8618805B-A0E5-4B0A-B52D-FF5429D814E2} {020FC895-5E41-41A6-9C10-E2BCEBE40842} = {8618805B-A0E5-4B0A-B52D-FF5429D814E2} {DCFF64BC-6B91-4121-BB4B-0A34AD3A6C84} = {8618805B-A0E5-4B0A-B52D-FF5429D814E2} {12E1D11E-6E0E-4F40-91BB-996E71CC15C3} = {6BD6DACA-80E0-4683-A6B3-649D79F8994C} {A3ECA132-FE31-46DF-8715-285B41409A1D} = {8975828E-1794-41B6-8F82-41F70F52C270} EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {6CA5CC96-0678-4723-B5B3-E2464516C277}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6CA5CC96-0678-4723-B5B3-E2464516C277}.Debug|Any CPU.Build.0 = Debug|Any CPU {6CA5CC96-0678-4723-B5B3-E2464516C277}.Release|Any CPU.ActiveCfg = Release|Any CPU {6CA5CC96-0678-4723-B5B3-E2464516C277}.Release|Any CPU.Build.0 = Release|Any CPU {71788840-6B85-42A5-9D52-D51A802A21BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {71788840-6B85-42A5-9D52-D51A802A21BE}.Debug|Any CPU.Build.0 = Debug|Any CPU {71788840-6B85-42A5-9D52-D51A802A21BE}.Release|Any CPU.ActiveCfg = Release|Any CPU {71788840-6B85-42A5-9D52-D51A802A21BE}.Release|Any CPU.Build.0 = Release|Any CPU {5EB40414-02BE-44A5-A14C-E619914A0F4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5EB40414-02BE-44A5-A14C-E619914A0F4A}.Debug|Any CPU.Build.0 = Debug|Any CPU {5EB40414-02BE-44A5-A14C-E619914A0F4A}.Release|Any CPU.ActiveCfg = Release|Any CPU {5EB40414-02BE-44A5-A14C-E619914A0F4A}.Release|Any CPU.Build.0 = Release|Any CPU {AD793B6C-DF05-458E-854B-ECFCAF7167AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD793B6C-DF05-458E-854B-ECFCAF7167AD}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD793B6C-DF05-458E-854B-ECFCAF7167AD}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD793B6C-DF05-458E-854B-ECFCAF7167AD}.Release|Any CPU.Build.0 = Release|Any CPU {96598D5F-199D-45E7-9F80-98FD10DCD24A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {96598D5F-199D-45E7-9F80-98FD10DCD24A}.Debug|Any CPU.Build.0 = Debug|Any CPU {96598D5F-199D-45E7-9F80-98FD10DCD24A}.Release|Any CPU.ActiveCfg = Release|Any CPU {96598D5F-199D-45E7-9F80-98FD10DCD24A}.Release|Any CPU.Build.0 = Release|Any CPU {0D8831BD-6C91-49ED-9BE7-AEA7A6DA821F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0D8831BD-6C91-49ED-9BE7-AEA7A6DA821F}.Debug|Any CPU.Build.0 = Debug|Any CPU {0D8831BD-6C91-49ED-9BE7-AEA7A6DA821F}.Release|Any CPU.ActiveCfg = Release|Any CPU {0D8831BD-6C91-49ED-9BE7-AEA7A6DA821F}.Release|Any CPU.Build.0 = Release|Any CPU {E6AFFD49-C560-4947-8076-48E3F87AACAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E6AFFD49-C560-4947-8076-48E3F87AACAC}.Debug|Any CPU.Build.0 = Debug|Any CPU {E6AFFD49-C560-4947-8076-48E3F87AACAC}.Release|Any CPU.ActiveCfg = Release|Any CPU {E6AFFD49-C560-4947-8076-48E3F87AACAC}.Release|Any CPU.Build.0 = Release|Any CPU {D7F4582E-2A51-4BCA-A4D6-A11B92EDAA2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D7F4582E-2A51-4BCA-A4D6-A11B92EDAA2F}.Debug|Any CPU.Build.0 = Debug|Any CPU {D7F4582E-2A51-4BCA-A4D6-A11B92EDAA2F}.Release|Any CPU.ActiveCfg = Release|Any CPU {D7F4582E-2A51-4BCA-A4D6-A11B92EDAA2F}.Release|Any CPU.Build.0 = Release|Any CPU {020FC895-5E41-41A6-9C10-E2BCEBE40842}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {020FC895-5E41-41A6-9C10-E2BCEBE40842}.Debug|Any CPU.Build.0 = Debug|Any CPU {020FC895-5E41-41A6-9C10-E2BCEBE40842}.Release|Any CPU.ActiveCfg = Release|Any CPU {020FC895-5E41-41A6-9C10-E2BCEBE40842}.Release|Any CPU.Build.0 = Release|Any CPU {DCFF64BC-6B91-4121-BB4B-0A34AD3A6C84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DCFF64BC-6B91-4121-BB4B-0A34AD3A6C84}.Debug|Any CPU.Build.0 = Debug|Any CPU {DCFF64BC-6B91-4121-BB4B-0A34AD3A6C84}.Release|Any CPU.ActiveCfg = Release|Any CPU {DCFF64BC-6B91-4121-BB4B-0A34AD3A6C84}.Release|Any CPU.Build.0 = Release|Any CPU {12E1D11E-6E0E-4F40-91BB-996E71CC15C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {12E1D11E-6E0E-4F40-91BB-996E71CC15C3}.Debug|Any CPU.Build.0 = Debug|Any CPU {12E1D11E-6E0E-4F40-91BB-996E71CC15C3}.Release|Any CPU.ActiveCfg = Release|Any CPU {12E1D11E-6E0E-4F40-91BB-996E71CC15C3}.Release|Any CPU.Build.0 = Release|Any CPU {A3ECA132-FE31-46DF-8715-285B41409A1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A3ECA132-FE31-46DF-8715-285B41409A1D}.Debug|Any CPU.Build.0 = Debug|Any CPU {A3ECA132-FE31-46DF-8715-285B41409A1D}.Release|Any CPU.ActiveCfg = Release|Any CPU {A3ECA132-FE31-46DF-8715-285B41409A1D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal