Skip to content

Commit

Permalink
Aspirfy!
Browse files Browse the repository at this point in the history
  • Loading branch information
davidfowl committed Nov 14, 2024
1 parent abd9421 commit 6b9f07e
Show file tree
Hide file tree
Showing 23 changed files with 284 additions and 355 deletions.
21 changes: 10 additions & 11 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,21 @@
<PackageVersion Include="Microsoft.AspNetCore.Authentication.Google" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.0" />
<PackageVersion Include="Yarp.ReverseProxy" Version="2.1.0" />
<PackageVersion Include="Microsoft.Tye.Extensions.Configuration" Version="0.10.0-alpha.21420.1" />
<PackageVersion Include="Yarp.ReverseProxy" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0" PrivateAssets="all" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery.Yarp" Version="9.0.0" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="9.0.0" />
</ItemGroup>
<!-- OpenTelemetry -->
<ItemGroup>
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.7.0" />
<PackageVersion Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.7.0-rc.1" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.EventCounters" Version="1.5.1-alpha.1" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.0.0-beta.8" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.7.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Process" Version="0.5.0-beta.3" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.5.1" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
</ItemGroup>
</Project>
82 changes: 3 additions & 79 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,64 +33,8 @@ It showcases:
1. Learn more about [dotnet-ef](https://learn.microsoft.com/en-us/ef/core/cli/dotnet)

### Running the application
To run the application, run both the [Todo.Web/Server](Todo.Web/Server) and [TodoApi](TodoApi). Below are different ways to run both applications:
- **Visual Studio** - Setup multiple startup projects by right clicking on the solution and selecting Properties. Select `TodoApi` and `Todo.Web.Server` as startup projects.

<img width="591" alt="image" src="https://user-images.githubusercontent.com/95136/204311327-479445c8-4f73-4845-b146-d56be8ceb9ab.png">

- **Visual Studio Code** - A `compound` launch definition is provided in the `launch.json` file, use the 'Run and Debug' view and select 'Web and API' and start that profile.

![image](https://github.com/timheuer/TodoApi/assets/4821/dfa83682-86c4-45ae-965b-fa6f6a6f07a9)


- **Terminal/CLI** - Open up 2 terminal windows, one in [Todo.Web.Server](Todo.Web/Server/) and the other in [TodoApi](TodoApi/) run:

```
dotnet watch run -lp https
```
This will run both applications with the `https` profile.
- **Tye** - Install the global tool using the following command:
```
dotnet tool install --global Microsoft.Tye --version 0.11.0-alpha.22111.1
```
Run `tye run` in the repository root and navigate to the tye dashboard (usually http://localhost:8000) to see both applications running.
- **Docker Compose** - Open your terminal, navigate to the root folder of this project and run the following commands:
1. Build a docker image for the `TodoApi` directly from dotnet publish.
```
dotnet publish ./TodoApi/TodoApi.csproj --os linux --arch x64 /t:PublishContainer -c Release
```
1. Build a docker image for the `Todo.Web.Server` directly from dotnet publish.
```
dotnet publish ./Todo.Web/Server/Todo.Web.Server.csproj --os linux --arch x64 /t:PublishContainer -c Release --self-contained true
```
1. Generate certificate and configure local machine so we can start our apps with https support using docker compose.
Windows using Linux containers
```
set PASSWORD YourPasswordHere
dotnet dev-certs https -ep ${HOME}/.aspnet/https/todoapps.pfx -p $PASSWORD --trust
```
macOS or Linux
```
export PASSWORD=YourPasswordHere
dotnet dev-certs https -ep ~/.aspnet/https/todoapps.pfx -p $PASSWORD --trust
```
1. Change these variables below in the `docker-compose.yml` file to match your https certificate and password.
- `ASPNETCORE_Kestrel__Certificates__Default__Password`
- `ASPNETCORE_Kestrel__Certificates__Default__Path`
1. Run `docker-compose up -d` to spin up both apps todo-api and todo-web-server plus jaeger and prometheus.
1. Navigate to the Todo Web app https://localhost:5003.

To run the application, run the [TodoApi.AppHost](TodoApi.AppHost) project. This uses .NET Aspire to run both the [Todo.Web/Server](Todo.Web/Server) and [TodoApi](TodoApi).

## Optional

Expand Down Expand Up @@ -188,26 +132,6 @@ This sample has **Auth0** configured as an OIDC server. It can be configured wit
Learn more about the Auth0 .NET SDK [here](https://github.com/auth0/auth0-aspnetcore-authentication).

### OpenTelemetry
TodoApi uses OpenTelemetry to collect logs, metrics and spans.

If you wish to view the collected telemetry, follow the steps below.

#### Metrics
1. Run Prometheus with Docker:
```
docker run -d -p 9090:9090 --name prometheus -v $PWD/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus
```
1. Open [Prometheus in your browser](http://localhost:9090/)
1. Query the collected metrics

#### Spans

1. Configure environment variable `OTEL_EXPORTER_OTLP_ENDPOINT` with the right endpoint URL to enable `.AddOtlpExporter` below `builder.Services.AddOpenTelemetryTracing`, in the `TodoApi/OpenTelemetryExtensions.cs` file
1. Run Jaeger with Docker:

```
docker run -d --name jaeger -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 -e COLLECTOR_OTLP_ENABLED=true -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 4317:4317 -p 4318:4318 -p 14250:14250 -p 14268:14268 -p 14269:14269 -p 9411:9411 jaegertracing/all-in-one:latest
```

1. Open [Jaeger in your browser](http://localhost:16686/)
1. View the collected spans
TodoApi uses OpenTelemetry to collect logs, metrics and spans. You can see this
using the [Aspire Dashboard](https://aspiredashboard.com/).
2 changes: 1 addition & 1 deletion Todo.Web/Server/AuthApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public static RouteGroupBuilder MapAuth(this IEndpointRouteBuilder routes)
// This name maps to the registered authentication scheme names in AuthenticationExtensions.cs
return Results.Challenge(
properties: new() { RedirectUri = $"/auth/signin/{provider}" },
authenticationSchemes: new[] { provider });
authenticationSchemes: [provider]);
});

group.MapGet("signin/{provider}", async (string provider, AuthClient client, HttpContext context) =>
Expand Down
14 changes: 7 additions & 7 deletions Todo.Web/Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();

// Configure auth with the front end
builder.AddAuthentication();
builder.Services.AddAuthorizationBuilder();
Expand All @@ -14,20 +16,18 @@
.AddInteractiveWebAssemblyComponents();

// Add the forwarder to make sending requests to the backend easier
builder.Services.AddHttpForwarder();

var todoUrl = builder.Configuration.GetServiceUri("todoapi")?.ToString() ??
builder.Configuration["TodoApiUrl"] ??
throw new InvalidOperationException("Todo API URL is not configured");
builder.Services.AddHttpForwarderWithServiceDiscovery();

// Configure the HttpClient for the backend API
builder.Services.AddHttpClient<AuthClient>(client =>
{
client.BaseAddress = new(todoUrl);
client.BaseAddress = new("http://todoapi");
});

var app = builder.Build();

app.MapDefaultEndpoints();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
Expand All @@ -48,7 +48,7 @@

// Configure the APIs
app.MapAuth();
app.MapTodos(todoUrl);
app.MapTodos();

app.Run();

3 changes: 2 additions & 1 deletion Todo.Web/Server/Todo.Web.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" />
<PackageReference Include="Yarp.ReverseProxy" />
<PackageReference Include="Microsoft.Tye.Extensions.Configuration" />
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery.Yarp" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\TodoApi.ServiceDefaults\TodoApi.ServiceDefaults.csproj" />
<ProjectReference Include="..\Client\Todo.Web.Client.csproj" />
<ProjectReference Include="..\Shared\Todo.Web.Shared.csproj" />
</ItemGroup>
Expand Down
5 changes: 2 additions & 3 deletions Todo.Web/Server/TodoApi.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
using Microsoft.AspNetCore.Authentication;
using Yarp.ReverseProxy.Forwarder;
using Yarp.ReverseProxy.Transforms;
using Yarp.ReverseProxy.Transforms.Builder;

namespace Todo.Web.Server;

public static class TodoApi
{
public static RouteGroupBuilder MapTodos(this IEndpointRouteBuilder routes, string todoUrl)
public static RouteGroupBuilder MapTodos(this IEndpointRouteBuilder routes)
{
// The todo API translates the authentication cookie between the browser the BFF into an
// access token that is sent to the todo API. We're using YARP to forward the request.
Expand All @@ -16,7 +15,7 @@ public static RouteGroupBuilder MapTodos(this IEndpointRouteBuilder routes, stri

group.RequireAuthorization();

group.MapForwarder("{*path}", todoUrl, new ForwarderRequestConfig(), b =>
group.MapForwarder("{*path}", "http://todoapi", new ForwarderRequestConfig(), b =>
{
b.AddRequestTransform(async c =>
{
Expand Down
8 changes: 8 additions & 0 deletions TodoApi.AppHost/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var builder = DistributedApplication.CreateBuilder(args);

var todoapi = builder.AddProject<Projects.TodoApi>("todoapi");

builder.AddProject<Projects.Todo_Web_Server>("todo-web-server")
.WithReference(todoapi);

builder.Build().Run();
29 changes: 29 additions & 0 deletions TodoApi.AppHost/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:17249;http://localhost:15169",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21226",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22195"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15169",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19224",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20024"
}
}
}
}
23 changes: 23 additions & 0 deletions TodoApi.AppHost/TodoApi.AppHost.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0" />

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<UserSecretsId>22f8485f-c345-41fa-9f21-ba96b1e511d1</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Todo.Web\Server\Todo.Web.Server.csproj" />
<ProjectReference Include="..\TodoApi\TodoApi.csproj" />
</ItemGroup>

</Project>
8 changes: 8 additions & 0 deletions TodoApi.AppHost/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions TodoApi.AppHost/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}
Loading

0 comments on commit 6b9f07e

Please sign in to comment.