Skip to content

Commit 58bc4e5

Browse files
committed
feat: updated sample app to use Minimal API
1 parent 8e17eda commit 58bc4e5

16 files changed

Lines changed: 468 additions & 91 deletions

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ interface IEntityStoreTelemetry
6666
}
6767
```
6868

69-
Checkout the [.NET Aspire Sample](https://github.com/purview-dev/purview-telemetry-sourcegenerator/tree/main/samples/SampleApp) Project to see the Activities, Logging, and Metrics working with the dashaboard.
70-
7169
For more information see the [wiki](https://github.com/purview-dev/purview-telemetry-sourcegenerator/wiki).
70+
71+
Checkout the [.NET Aspire Sample](https://github.com/purview-dev/purview-telemetry-sourcegenerator/tree/main/samples/SampleApp) Project to see the Activities, Logging, and Metrics working with the Aspire Dashboard.
72+
73+
> This sample project has `EmitCompilerGeneratedFiles` set to `true`, so you can easily see the generated output.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using SampleApp.Host.Services;
3+
4+
record DefaultWeatherRequest(
5+
[FromServices] IWeatherService WeatherService,
6+
CancellationToken Token);
7+
8+
record WeatherRequest(
9+
int RequestCount,
10+
[FromServices] IWeatherService WeatherService,
11+
CancellationToken Token);
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using Microsoft.AspNetCore.Http.HttpResults;
2+
3+
namespace SampleApp.Host.APIs;
4+
5+
static class WeatherAPI
6+
{
7+
public static IEndpointRouteBuilder MapWeatherAPIv1(this IEndpointRouteBuilder app)
8+
{
9+
var api = app
10+
.MapGroup("/weatherforecast")
11+
//.MapToApiVersion(1.0)
12+
.WithDisplayName("Weather APIs")
13+
;
14+
15+
api.MapGet("/", GetDefaultWeatherRequestAsync)
16+
.WithDescription("Gets the weather forecasts, defaults to 5.")
17+
.WithDisplayName("5 Weather Forecasts")
18+
;
19+
20+
api.MapGet("/{requestCount:int}", GetWeatherRequestAsync)
21+
.WithDescription("Gets the weather forecasts.")
22+
.WithDisplayName("Weather Forecasts")
23+
;
24+
25+
return api;
26+
}
27+
28+
static async Task<Results<Ok<WeatherForecast[]>, NoContent, ProblemHttpResult>> GetDefaultWeatherRequestAsync([AsParameters] DefaultWeatherRequest request)
29+
{
30+
try
31+
{
32+
var results = await request.WeatherService.GetWeatherForecastsAsync(5, request.Token);
33+
return results.Any()
34+
? TypedResults.Ok(results.ToArray())
35+
: TypedResults.NoContent();
36+
}
37+
catch (Exception ex)
38+
{
39+
return TypedResults.Problem(detail: ex.Message, statusCode: 502);
40+
}
41+
}
42+
43+
static async Task<Results<Ok<WeatherForecast[]>, NoContent, ProblemHttpResult, BadRequest<string>>> GetWeatherRequestAsync([AsParameters] WeatherRequest request)
44+
{
45+
try
46+
{
47+
var results = await request.WeatherService.GetWeatherForecastsAsync(request.RequestCount, request.Token);
48+
return results.Any()
49+
? TypedResults.Ok(results.ToArray())
50+
: TypedResults.NoContent();
51+
}
52+
catch (ArgumentOutOfRangeException ex)
53+
{
54+
return TypedResults.BadRequest(ex.Message);
55+
}
56+
catch (Exception ex)
57+
{
58+
return TypedResults.Problem(detail: ex.Message, statusCode: 502);
59+
}
60+
}
61+
}

samples/SampleApp/SampleApp.Host/Controllers/WeatherForecastController.cs

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,31 @@
1+
using SampleApp.Host.APIs;
12
using SampleApp.Host.Services;
23

3-
namespace SampleApp.Host;
4+
var builder = WebApplication.CreateSlimBuilder(args);
45

5-
public class Program
6-
{
7-
public static void Main(string[] args)
8-
{
9-
var builder = WebApplication.CreateBuilder(args);
10-
builder.AddServiceDefaults();
11-
builder.Services.AddMetrics();
6+
builder
7+
.AddServiceDefaults()
8+
.AddDefaultOpenAPI(
9+
//builder.Services.AddApiVersioning()
10+
)
11+
;
1212

13-
// Add services to the container.
13+
builder.Services
14+
.AddScoped<IWeatherService, WeatherService>()
15+
.AddWeatherServiceTelemetry()
16+
;
1417

15-
// This is a generated method that adds the
16-
// IWeatherServiceTelemetry interface to the container
17-
// as a singleton.
18-
builder.Services.AddWeatherServiceTelemetry();
18+
var app = builder.Build();
1919

20-
builder.Services.AddTransient<IWeatherService, WeatherService>();
20+
app.MapDefaultEndpoints();
2121

22-
builder.Services.AddControllers();
23-
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
24-
builder.Services.AddEndpointsApiExplorer();
25-
builder.Services.AddSwaggerGen();
22+
//app
23+
//.NewVersionedApi("Weather API")
24+
//.MapToApiVersion(1.0)
25+
//;
2626

27-
var app = builder.Build();
27+
app.MapWeatherAPIv1();
2828

29-
app.MapDefaultEndpoints();
29+
app.UseDefaultOpenAPI();
3030

31-
// Configure the HTTP request pipeline.
32-
if (app.Environment.IsDevelopment())
33-
{
34-
app.UseSwagger();
35-
app.UseSwaggerUI();
36-
}
37-
38-
app.UseHttpsRedirection();
39-
40-
app.UseAuthorization();
41-
42-
app.MapControllers();
43-
44-
app.Run();
45-
}
46-
}
31+
await app.RunAsync();

samples/SampleApp/SampleApp.Host/Properties/launchSettings.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"commandName": "Project",
1414
"dotnetRunMessages": true,
1515
"launchBrowser": true,
16-
"launchUrl": "swagger",
16+
"launchUrl": "",
1717
"applicationUrl": "http://localhost:5275",
1818
"environmentVariables": {
1919
"ASPNETCORE_ENVIRONMENT": "Development"
@@ -23,7 +23,7 @@
2323
"commandName": "Project",
2424
"dotnetRunMessages": true,
2525
"launchBrowser": true,
26-
"launchUrl": "swagger",
26+
"launchUrl": "",
2727
"applicationUrl": "https://localhost:7015;http://localhost:5275",
2828
"environmentVariables": {
2929
"ASPNETCORE_ENVIRONMENT": "Development"
@@ -32,7 +32,7 @@
3232
"IIS Express": {
3333
"commandName": "IISExpress",
3434
"launchBrowser": true,
35-
"launchUrl": "swagger",
35+
"launchUrl": "",
3636
"environmentVariables": {
3737
"ASPNETCORE_ENVIRONMENT": "Development"
3838
}

samples/SampleApp/SampleApp.Host/SampleApp.Host.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
<PrivateAssets>all</PrivateAssets>
1515
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
1616
</PackageReference>
17-
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
1817
</ItemGroup>
1918

2019
<ItemGroup>

samples/SampleApp/SampleApp.Host/Services/IWeatherService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22

33
public interface IWeatherService
44
{
5-
IEnumerable<WeatherForecast> GetWeatherForecastsAsync(int requestCount, CancellationToken cancellationToken = default);
5+
Task<IEnumerable<WeatherForecast>> GetWeatherForecastsAsync(int requestCount, CancellationToken cancellationToken = default);
66
}

samples/SampleApp/SampleApp.Host/Services/IWeatherServiceTelemetry.cs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,48 @@ namespace SampleApp.Host.Services;
1919
[Meter]
2020
public interface IWeatherServiceTelemetry
2121
{
22+
// --> Start: Activities
23+
2224
[Activity(ActivityKind.Client)]
23-
Activity? GettingWeatherForecastFromUpstreamService([Baggage] string someRandomBaggageInfo, int requestedCount, int validatedRequestedCount);
25+
Activity? GettingWeatherForecastFromUpstreamService([Baggage] string someRandomBaggageInfo, int requestedCount);
2426

2527
[Event]
2628
void ForecastReceived(Activity? activity, int minTempInC, int maxTempInC);
2729

28-
[Event]
30+
[Event(ActivityStatusCode.Error)]
2931
void FailedToRetrieveForecast(Activity? activity, Exception ex);
3032

33+
[Event(ActivityStatusCode.Ok)]
34+
void TemperaturesReceived(Activity? activity, TimeSpan elapsed);
35+
36+
// --> END: Activities
37+
38+
// --> START: Meters
39+
3140
[AutoCounter]
3241
void WeatherForecastRequested();
3342

3443
[AutoCounter]
3544
void ItsTooCold(int tooColdCount);
3645

46+
[Histogram]
47+
void HistogramOfTemperature(int temperature);
48+
49+
// --> END: Meters
50+
51+
// --> START: Logs
52+
3753
[Log(LogLevel.Warning)]
3854
void TemperatureOutOfRange(int minTempInC);
3955

40-
[Warning]
41-
void RequestedCountIsTooSmall(int requestCount, int validatedRequestedCount);
56+
[Error]
57+
void RequestedCountIsTooSmall(int requestCount);
4258

4359
[Info]
44-
void TemperatureWithinRange();
60+
void TemperaturesWithinRange();
4561

46-
[Error]
62+
[Critical]
4763
void WeatherForecastRequestFailed(Exception ex);
64+
65+
// --> END: Logs
4866
}
Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
1-
namespace SampleApp.Host.Services;
1+
using System.Diagnostics;
2+
3+
namespace SampleApp.Host.Services;
24

35
sealed class WeatherService(IWeatherServiceTelemetry telemetry) : IWeatherService
46
{
5-
const int _tooColdTempInC = -10;
7+
const int TooColdTempInC = -10;
68

7-
static readonly string[] _summaries =
9+
static readonly string[] Summaries =
810
[
911
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
1012
];
1113

12-
public IEnumerable<WeatherForecast> GetWeatherForecastsAsync(int requestCount, CancellationToken cancellationToken = default)
14+
public Task<IEnumerable<WeatherForecast>> GetWeatherForecastsAsync(int requestCount, CancellationToken cancellationToken = default)
1315
{
14-
var validatedRequestedCount = requestCount;
15-
if (validatedRequestedCount < 5)
16+
const int minRequestCount = 5;
17+
const int maxRequestCount = 20;
18+
19+
if (requestCount < minRequestCount || requestCount > maxRequestCount)
1620
{
17-
validatedRequestedCount = 5;
21+
telemetry.RequestedCountIsTooSmall(requestCount);
1822

19-
telemetry.RequestedCountIsTooSmall(requestCount, validatedRequestedCount);
23+
throw new ArgumentOutOfRangeException(nameof(requestCount), $"Requested count must be at least {minRequestCount}, and no greater than {maxRequestCount}.");
2024
}
2125

22-
using var activity = telemetry.GettingWeatherForecastFromUpstreamService($"{Guid.NewGuid()}",
23-
requestCount,
24-
validatedRequestedCount);
26+
var sw = Stopwatch.StartNew();
27+
using var activity = telemetry.GettingWeatherForecastFromUpstreamService($"{Guid.NewGuid()}", requestCount);
2528

2629
telemetry.WeatherForecastRequested();
2730

@@ -39,27 +42,35 @@ public IEnumerable<WeatherForecast> GetWeatherForecastsAsync(int requestCount, C
3942
throw ex;
4043
}
4144

42-
var results = Enumerable.Range(1, validatedRequestedCount).Select(index => new WeatherForecast
45+
var results = Enumerable.Range(1, requestCount).Select(index => new WeatherForecast
4346
{
44-
Date = DateOnly.FromDateTime(DateTime.UtcNow.AddDays(index)),
47+
Date = DateOnly.FromDateTime(DateTime.UtcNow.AddDays(--index)),
4548
TemperatureC = Random.Shared.Next(-20, 55),
46-
Summary = _summaries[Random.Shared.Next(_summaries.Length)]
49+
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
4750
}).ToArray();
4851

52+
foreach (var wf in results)
53+
telemetry.HistogramOfTemperature(wf.TemperatureC);
54+
4955
var minTempInC = results.Min(m => m.TemperatureC);
5056
telemetry.ForecastReceived(activity,
5157
minTempInC,
5258
results.Max(wf => wf.TemperatureC)
5359
);
5460

55-
if (minTempInC < _tooColdTempInC)
61+
if (minTempInC < TooColdTempInC)
5662
{
5763
telemetry.TemperatureOutOfRange(minTempInC);
58-
telemetry.ItsTooCold(results.Count(wf => wf.TemperatureC < _tooColdTempInC));
64+
telemetry.ItsTooCold(results.Count(wf => wf.TemperatureC < TooColdTempInC));
5965
}
6066
else
61-
telemetry.TemperatureWithinRange();
67+
telemetry.TemperaturesWithinRange();
68+
69+
sw.Stop();
70+
71+
telemetry.TemperaturesReceived(activity, sw.Elapsed);
6272

63-
return results;
73+
// This isn't really async, we're just pretending.
74+
return Task.FromResult(results.AsEnumerable());
6475
}
6576
}

0 commit comments

Comments
 (0)