Skip to content

Commit

Permalink
Merge pull request #1 from neozhu/addapiclient
Browse files Browse the repository at this point in the history
Add apiclient and login / logout
  • Loading branch information
neozhu authored Nov 16, 2024
2 parents 33ed337 + 75c8c18 commit e131137
Show file tree
Hide file tree
Showing 139 changed files with 5,434 additions and 748 deletions.
81 changes: 0 additions & 81 deletions CleanAspire.sln

This file was deleted.

2 changes: 1 addition & 1 deletion CleanAspire.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<Project Path="src/CleanAspire.Api/CleanAspire.Api.csproj" Id="ded5e19f-db6b-c4ee-e692-cffe0619c173" />
<Project Path="src/CleanAspire.AppHost/CleanAspire.AppHost.csproj" />
<Project Path="src/CleanAspire.Application/CleanAspire.Application.csproj" Id="06710e4a-8503-48b5-b25b-d1056a7414eb" />
<Project Path="src/CleanAspire.ClientApp/CleanAspire.ClientApp.csproj" />
<Project Path="src/CleanAspire.Domain/CleanAspire.Domain.csproj" Id="dfaf6933-e1d7-4eac-b854-fe12bc19d9ef" />
<Project Path="src/CleanAspire.Infrastructure/CleanAspire.Infrastructure.csproj" Id="abe1716e-889c-48b6-8aa0-51d688f3c480" />
<Project Path="src/CleanAspire.PWA/CleanAspire.PWA.csproj" Id="3fc79b0c-9d07-0c1f-fc23-ea8c2e02c02c" />
<Project Path="src/CleanAspire.ServiceDefaults/CleanAspire.ServiceDefaults.csproj" />
</Folder>
<Folder Name="/src/Migrators/" Id="c983071d-42d7-4326-a379-ce622e29d307">
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
## CleanAspire - Modern .NET 9 Minimal API + Blazor WebAssembly PWA Template

![blazorclient](https://github.com/user-attachments/assets/013b167b-59fa-42d7-a2f7-ffec301c4e11)
### Overview

**CleanAspire** is a cutting-edge open-source project combining the latest .NET 9 Minimal API with Blazor WebAssembly, all organized with the principles of **Clean Architecture**. This template is built to accelerate the development of scalable and maintainable Progressive Web Applications (PWA) while keeping the codebase neat, modular, and future-proof.


### Features

- **.NET 9 Minimal API** for lightweight, high-performance backend services.
Expand Down
7 changes: 6 additions & 1 deletion src/CleanAspire.Api/CleanAspire.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,19 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0-rc.2.24474.1"/>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0-rc.2.24474.1" />
<PackageReference Include="Scalar.AspNetCore" Version="1.2.37" />

</ItemGroup>



<ItemGroup>
<ProjectReference Include="..\CleanAspire.ServiceDefaults\CleanAspire.ServiceDefaults.csproj" />
<ProjectReference Include="..\Migrators\Migrators.MSSQL\Migrators.MSSQL.csproj" />
<ProjectReference Include="..\Migrators\Migrators.PostgreSQL\Migrators.PostgreSQL.csproj" />
<ProjectReference Include="..\Migrators\Migrators.SQLite\Migrators.SQLite.csproj" />

</ItemGroup>

Expand Down
Binary file modified src/CleanAspire.Api/CleanAspireDb.db
Binary file not shown.
Binary file modified src/CleanAspire.Api/CleanAspireDb.db-shm
Binary file not shown.
Binary file modified src/CleanAspire.Api/CleanAspireDb.db-wal
Binary file not shown.
24 changes: 24 additions & 0 deletions src/CleanAspire.Api/IdentityApiAdditionalEndpointsExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.AspNetCore.Identity;

namespace CleanAspire.Api;

public static class IdentityApiAdditionalEndpointsExtensions
{
public static IEndpointRouteBuilder MapIdentityApiAdditionalEndpoints<TUser>(this IEndpointRouteBuilder endpoints)
where TUser : class, new()
{
ArgumentNullException.ThrowIfNull(endpoints);
endpoints.MapPost("/logout", async (SignInManager<TUser> signInManager) =>
{
await signInManager.SignOutAsync();
return Results.Ok();
}).RequireAuthorization();

return endpoints;
}
}

73 changes: 67 additions & 6 deletions src/CleanAspire.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,46 @@
using CleanAspire.Infrastructure.Persistence;
using CleanAspire.Api;
using CleanAspire.Application;
using CleanAspire.Application.Common.Interfaces;
using CleanAspire.Application.Common.Services;
using CleanAspire.Domain.Entities;
using CleanAspire.Domain.Identities;
using CleanAspire.Infrastructure;
using CleanAspire.Infrastructure.Persistence;
using CleanAspire.Infrastructure.Persistence.Seed;
using CleanAspire.Infrastructure.Services;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Mono.TextTemplating;
using Scalar.AspNetCore;

var builder = WebApplication.CreateBuilder(args);




builder.Services.AddHttpContextAccessor();
builder.Services.AddApplication();
builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme).AddIdentityCookies();
builder.Services.AddAuthorizationBuilder();

builder.Services.AddDatabase(builder.Configuration);
builder.Services.AddIdentityCore<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddApiEndpoints();
// add a CORS policy for the client
builder.Services.AddCors(
options => options.AddPolicy(
"wasm",
policy => policy.WithOrigins("localhost", "https://localhost:7341", "https://localhost:7123")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()));

builder.Services.AddOpenApi();
builder.Services.AddServiceDiscovery();

// Add service defaults & Aspire client integrations.
builder.AddServiceDefaults();

// Add services to the container.
builder.Services.AddProblemDetails();

Expand All @@ -17,10 +53,12 @@
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", ( ) =>
app.UseCors("wasm");
app.MapGet("/weatherforecast", async (IApplicationDbContext db) =>
{

var product = new Product() { Id = Guid.CreateVersion7().ToString(), Name = "test" + Guid.CreateVersion7().ToString(), Description = "test", Currency = "USD", Price = 100, Quantity = 99, UOM = "EA" };
db.Products.Add(product);
await db.SaveChangesAsync();
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
Expand All @@ -32,11 +70,34 @@
return forecast;
});

app.MapDefaultEndpoints();
app.Use(async (context, next) =>
{
var currentUserContextSetter = context.RequestServices.GetRequiredService<ICurrentUserContextSetter>();
try
{
currentUserContextSetter.SetCurrentUser(context.User);
await next.Invoke();
}
finally
{
currentUserContextSetter.Clear();
}
});

app.MapDefaultEndpoints();
app.MapIdentityApi<ApplicationUser>();
app.MapIdentityApiAdditionalEndpoints<ApplicationUser>();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
app.MapScalarApiReference();
}
await app.RunAsync();

record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}



7 changes: 5 additions & 2 deletions src/CleanAspire.AppHost/CleanAspire.AppHost.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@

<ItemGroup>
<ProjectReference Include="..\CleanAspire.Api\CleanAspire.Api.csproj" />
<ProjectReference Include="..\CleanAspire.PWA\CleanAspire.PWA.csproj" />
<ProjectReference Include="..\CleanAspire.ClientApp\CleanAspire.ClientApp.csproj" />
<ProjectReference Include="..\Migrators\Migrators.MSSQL\Migrators.MSSQL.csproj" />
<ProjectReference Include="..\Migrators\Migrators.PostgreSQL\Migrators.PostgreSQL.csproj" />
<ProjectReference Include="..\Migrators\Migrators.SQLite\Migrators.SQLite.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.0.0-rc.1.24511.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0-rc.2.24474.1"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0-rc.2.24474.1" />
</ItemGroup>

</Project>
6 changes: 3 additions & 3 deletions src/CleanAspire.AppHost/Program.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
var builder = DistributedApplication.CreateBuilder(args);
var builder = DistributedApplication.CreateBuilder(args);

var apiService = builder.AddProject<Projects.CleanAspire_Api>("apiservice");

builder.AddProject<Projects.CleanAspire_PWA>("webfrontend")
.WithExternalHttpEndpoints()
builder.AddProject<Projects.CleanAspire_ClientApp>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(apiService)
.WaitFor(apiService);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Security.Claims;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CleanAspire.Application.Common.Interfaces;
namespace CleanAspire.Application.Common.Services;

/// <summary>
/// Interface to access the current user's session information.
/// </summary>
public interface ICurrentUserAccessor
{
string? UserId{ get; }
/// <summary>
/// Gets the current session information of the user.
/// </summary>
ClaimsPrincipal? User { get; }
string? UserId { get; }
string? TenantId { get; }
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Security.Claims;

namespace CleanAspire.Application.Common.Services;

/// <summary>
/// Interface representing the current user context.
/// </summary>
public interface ICurrentUserContext
{

ClaimsPrincipal? GetCurrentUser();

void Set(ClaimsPrincipal? user);
void Clear();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Security.Claims;

namespace CleanAspire.Application.Common.Services;

/// <summary>
/// Interface for setting and clearing the current user context.
/// </summary>
public interface ICurrentUserContextSetter
{
/// <summary>
/// Sets the current user context with the provided session information.
/// </summary>
/// <param name="user">The session information of the current user.</param>
void SetCurrentUser(ClaimsPrincipal user);

/// <summary>
/// Clears the current user context.
/// </summary>
void Clear();
}
27 changes: 27 additions & 0 deletions src/CleanAspire.Application/DependencyInjection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using MediatR.Pipeline;
using Microsoft.Extensions.DependencyInjection;

namespace CleanAspire.Application;

public static class DependencyInjection
{
public static IServiceCollection AddApplication(this IServiceCollection services)
{
services.AddMediatR(config =>
{
config.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
});
return services;
}
}

12 changes: 12 additions & 0 deletions src/CleanAspire.ClientApp/App.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
Loading

0 comments on commit e131137

Please sign in to comment.