Skip to content

Commit

Permalink
Feature/migrate to minimal api (dotnet-architecture#662)
Browse files Browse the repository at this point in the history
* migrate from classic controller to minimal api

* fix all PublicApi integration test

* update all nuget package add forget project

* fix pay now

* Adapt readme use in memory database

* undo AuthenticateEndpoint to use EndpointBaseAsync

* Update README.md

Co-authored-by: Steve Smith <steve@kentsmiths.com>

Co-authored-by: Steve Smith <steve@kentsmiths.com>
  • Loading branch information
michelcedric and ardalis authored Jan 21, 2022
1 parent 02b5097 commit 1e13733
Show file tree
Hide file tree
Showing 63 changed files with 842 additions and 630 deletions.
15 changes: 5 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,13 @@ You can also run the samples in Docker (see below).

### Configuring the sample to use SQL Server

1. Update `Startup.cs`'s `ConfigureDevelopmentServices` method as follows:
1. By default, the project uses a real database. If you want an in memory database, you can add in `appsettings.json`

```csharp
public void ConfigureDevelopmentServices(IServiceCollection services)
{
// use in-memory database
//ConfigureTestingServices(services);
```json
{
"UseOnlyInMemoryDatabase": true
}

// use real database
ConfigureProductionServices(services);

}
```

1. Ensure your connection strings in `appsettings.json` point to a local SQL Server instance.
Expand Down
7 changes: 7 additions & 0 deletions eShopOnWeb.sln
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorAdmin", "src\BlazorAd
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorShared", "src\BlazorShared\BlazorShared.csproj", "{715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PublicApiIntegrationTests", "tests\PublicApiIntegrationTests\PublicApiIntegrationTests.csproj", "{D53EF010-8F8C-4337-A059-456E19D8AE63}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -84,6 +86,10 @@ Global
{715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9}.Release|Any CPU.Build.0 = Release|Any CPU
{D53EF010-8F8C-4337-A059-456E19D8AE63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D53EF010-8F8C-4337-A059-456E19D8AE63}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D53EF010-8F8C-4337-A059-456E19D8AE63}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D53EF010-8F8C-4337-A059-456E19D8AE63}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -98,6 +104,7 @@ Global
{B5E4F33C-4667-4A55-AF6A-740F84C4CF3A} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
{71368733-80A4-4869-B215-3A7001878577} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
{715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
{D53EF010-8F8C-4337-A059-456E19D8AE63} = {15EA4737-125B-4E6E-A806-E13B7EBCDCCF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {49813262-5DA3-4D61-ABD3-493C74CE8C2B}
Expand Down
2 changes: 1 addition & 1 deletion src/ApplicationCore/ApplicationCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PackageReference Include="Ardalis.Specification" Version="5.2.0" />
<PackageReference Include="MediatR" Version="9.0.0" />
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
<PackageReference Include="System.Text.Json" Version="6.0.0" />
<PackageReference Include="System.Text.Json" Version="6.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
10 changes: 5 additions & 5 deletions src/BlazorAdmin/BlazorAdmin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
<ItemGroup>
<PackageReference Include="Blazored.LocalStorage" Version="4.1.5" />
<PackageReference Include="BlazorInputFile" Version="0.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="6.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="6.0.0" />
<PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/BlazorShared/BlazorShared.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<ItemGroup>
<PackageReference Include="BlazorInputFile" Version="0.2.0" />
<PackageReference Include="FluentValidation" Version="10.3.5" />
<PackageReference Include="FluentValidation" Version="10.3.6" />
</ItemGroup>

</Project>
40 changes: 40 additions & 0 deletions src/Infrastructure/Dependencies.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.Infrastructure.Data;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.eShopWeb.Infrastructure;

public static class Dependencies
{
public static void ConfigureServices(IConfiguration configuration, IServiceCollection services)
{
var useOnlyInMemoryDatabase = false;
if (configuration["UseOnlyInMemoryDatabase"] != null)
{
useOnlyInMemoryDatabase = bool.Parse(configuration["UseOnlyInMemoryDatabase"]);
}

if (useOnlyInMemoryDatabase)
{
services.AddDbContext<CatalogContext>(c =>
c.UseInMemoryDatabase("Catalog"));

services.AddDbContext<AppIdentityDbContext>(options =>
options.UseInMemoryDatabase("Identity"));
}
else
{
// use real database
// Requires LocalDB which can be installed with SQL Server Express 2016
// https://www.microsoft.com/en-us/download/details.aspx?id=54284
services.AddDbContext<CatalogContext>(c =>
c.UseSqlServer(configuration.GetConnectionString("CatalogConnection")));

// Add Identity DbContext
services.AddDbContext<AppIdentityDbContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("IdentityConnection")));
}
}
}
5 changes: 3 additions & 2 deletions src/Infrastructure/Infrastructure.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@

<ItemGroup>
<PackageReference Include="Ardalis.Specification.EntityFrameworkCore" Version="5.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.15.0" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@

namespace Microsoft.eShopWeb.PublicApi.AuthEndpoints;

public class Authenticate : EndpointBaseAsync
/// <summary>
/// Authenticates a user
/// </summary>
public class AuthenticateEndpoint : EndpointBaseAsync
.WithRequest<AuthenticateRequest>
.WithActionResult<AuthenticateResponse>
{
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly ITokenClaimsService _tokenClaimsService;

public Authenticate(SignInManager<ApplicationUser> signInManager,
public AuthenticateEndpoint(SignInManager<ApplicationUser> signInManager,
ITokenClaimsService tokenClaimsService)
{
_signInManager = signInManager;
Expand All @@ -30,7 +33,7 @@ public Authenticate(SignInManager<ApplicationUser> signInManager,
OperationId = "auth.authenticate",
Tags = new[] { "AuthEndpoints" })
]
public override async Task<ActionResult<AuthenticateResponse>> HandleAsync(AuthenticateRequest request, CancellationToken cancellationToken)
public override async Task<ActionResult<AuthenticateResponse>> HandleAsync(AuthenticateRequest request, CancellationToken cancellationToken = default)
{
var response = new AuthenticateResponse(request.CorrelationId());

Expand Down
48 changes: 48 additions & 0 deletions src/PublicApi/CatalogBrandEndpoints/CatalogBrandListEndpoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using MinimalApi.Endpoint;

namespace Microsoft.eShopWeb.PublicApi.CatalogBrandEndpoints;

/// <summary>
/// List Catalog Brands
/// </summary>
public class CatalogBrandListEndpoint : IEndpoint<IResult>
{
private IRepository<CatalogBrand> _catalogBrandRepository;
private readonly IMapper _mapper;

public CatalogBrandListEndpoint(IMapper mapper)
{
_mapper = mapper;
}

public void AddRoute(IEndpointRouteBuilder app)
{
app.MapGet("api/catalog-brands",
async (IRepository<CatalogBrand> catalogBrandRepository) =>
{
_catalogBrandRepository = catalogBrandRepository;
return await HandleAsync();
})
.Produces<ListCatalogBrandsResponse>()
.WithTags("CatalogBrandEndpoints");
}

public async Task<IResult> HandleAsync()
{
var response = new ListCatalogBrandsResponse();

var items = await _catalogBrandRepository.ListAsync();

response.CatalogBrands.AddRange(items.Select(_mapper.Map<CatalogBrandDto>));

return Results.Ok(response);
}
}
44 changes: 0 additions & 44 deletions src/PublicApi/CatalogBrandEndpoints/List.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints;

public class GetByIdCatalogItemRequest : BaseRequest
{
public int CatalogItemId { get; init; }

public GetByIdCatalogItemRequest(int catalogItemId)
{
CatalogItemId = catalogItemId;
}
}
56 changes: 56 additions & 0 deletions src/PublicApi/CatalogItemEndpoints/CatalogItemGetByIdEndpoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using MinimalApi.Endpoint;

namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints;

/// <summary>
/// Get a Catalog Item by Id
/// </summary>
public class CatalogItemGetByIdEndpoint : IEndpoint<IResult, GetByIdCatalogItemRequest>
{
private IRepository<CatalogItem> _itemRepository;
private readonly IUriComposer _uriComposer;

public CatalogItemGetByIdEndpoint(IUriComposer uriComposer)
{
_uriComposer = uriComposer;
}

public void AddRoute(IEndpointRouteBuilder app)
{
app.MapGet("api/catalog-items/{catalogItemId}",
async (int catalogItemId, IRepository<CatalogItem> itemRepository) =>
{
_itemRepository = itemRepository;
return await HandleAsync(new GetByIdCatalogItemRequest(catalogItemId));
})
.Produces<GetByIdCatalogItemResponse>()
.WithTags("CatalogItemEndpoints");
}

public async Task<IResult> HandleAsync(GetByIdCatalogItemRequest request)
{
var response = new GetByIdCatalogItemResponse(request.CorrelationId());

var item = await _itemRepository.GetByIdAsync(request.CatalogItemId);
if (item is null)
return Results.NotFound();

response.CatalogItem = new CatalogItemDto
{
Id = item.Id,
CatalogBrandId = item.CatalogBrandId,
CatalogTypeId = item.CatalogTypeId,
Description = item.Description,
Name = item.Name,
PictureUri = _uriComposer.ComposePicUri(item.PictureUri),
Price = item.Price
};
return Results.Ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints;

public class ListPagedCatalogItemRequest : BaseRequest
{
public int? PageSize { get; init; }
public int? PageIndex { get; init; }
public int? CatalogBrandId { get; init; }
public int? CatalogTypeId { get; init; }

public ListPagedCatalogItemRequest(int? pageSize, int? pageIndex, int? catalogBrandId, int? catalogTypeId)
{
PageSize = pageSize ?? 0;
PageIndex = pageIndex ?? 0;
CatalogBrandId = catalogBrandId;
CatalogTypeId = catalogTypeId;
}
}
Loading

0 comments on commit 1e13733

Please sign in to comment.