Skip to content

Commit

Permalink
Adds support for acting as a .NET Aspire client integration.
Browse files Browse the repository at this point in the history
  • Loading branch information
IEvangelist committed Dec 3, 2024
1 parent 11c6ede commit 272cc6b
Show file tree
Hide file tree
Showing 94 changed files with 62,831 additions and 34 deletions.
16 changes: 14 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Azure.Identity" Version="1.13.1" />
<PackageVersion Include="Aspire.Hosting.Azure.CosmosDB" Version="9.0.0" />
<PackageVersion Include="AspNetCore.HealthChecks.CosmosDb" Version="8.0.1" />
<PackageVersion Include="Bogus" Version="35.6.1" />
<PackageVersion Include="CorrelationId" Version="3.0.1" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="FluentAssertions" Version="6.12.2" />
<PackageVersion Include="FluentAssertions" Version="7.0.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="MartinCostello.Logging.XUnit" Version="0.4.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0" />
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.46.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="7.1.0" />
<PackageVersion Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
Expand All @@ -20,21 +23,30 @@
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0" />
<PackageVersion Include="Microsoft.NET.Sdk.Functions" Version="4.6.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="9.0.0" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.10.0" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.10.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.10.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
<PackageVersion Include="MinVer" Version="6.0.0" />
<PackageVersion Include="Moq.AutoMock" Version="3.5.0" />
<PackageVersion Include="Moq" Version="4.20.72" />
<PackageVersion Include="Mumby0168.CleanArchitecture.Exceptions.AspNetCore" Version="1.1.0" />
<PackageVersion Include="Mumby0168.CleanArchitecture.Exceptions" Version="1.0.0" />
<PackageVersion Include="Polly" Version="8.5.0" />
<PackageVersion Include="Scrutor" Version="5.0.2" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="7.0.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
<PackageVersion Include="System.Net.Http.Json" Version="9.0.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
Expand Down
28 changes: 28 additions & 0 deletions Microsoft.Azure.CosmosRepository.sln
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.CosmosEvent
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BugSandbox", "samples\Microsoft.Azure.CosmosRepository\BugSandbox\BugSandbox.csproj", "{7354577A-699D-4952-B8DF-27CF0FC7F683}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspireApp.AppHost", "samples\Microsoft.Azure.CosmosRepository\AspireApp\AspireApp.AppHost\AspireApp.AppHost.csproj", "{2A302849-3E35-42E5-A9CA-DC14B34476F0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspireApp.ServiceDefaults", "samples\Microsoft.Azure.CosmosRepository\AspireApp\AspireApp.ServiceDefaults\AspireApp.ServiceDefaults.csproj", "{CD50D0A9-F1EA-9983-6CCA-0E492FCDFC7C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspireApp.ApiService", "samples\Microsoft.Azure.CosmosRepository\AspireApp\AspireApp.ApiService\AspireApp.ApiService.csproj", "{9ACA5598-D93D-4956-A5BB-9311957301D6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspireApp.Web", "samples\Microsoft.Azure.CosmosRepository\AspireApp\AspireApp.Web\AspireApp.Web.csproj", "{CD93A91F-80F1-9232-0D40-5BCB93B297E9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -186,6 +194,22 @@ Global
{7354577A-699D-4952-B8DF-27CF0FC7F683}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7354577A-699D-4952-B8DF-27CF0FC7F683}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7354577A-699D-4952-B8DF-27CF0FC7F683}.Release|Any CPU.Build.0 = Release|Any CPU
{2A302849-3E35-42E5-A9CA-DC14B34476F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A302849-3E35-42E5-A9CA-DC14B34476F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A302849-3E35-42E5-A9CA-DC14B34476F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A302849-3E35-42E5-A9CA-DC14B34476F0}.Release|Any CPU.Build.0 = Release|Any CPU
{CD50D0A9-F1EA-9983-6CCA-0E492FCDFC7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD50D0A9-F1EA-9983-6CCA-0E492FCDFC7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD50D0A9-F1EA-9983-6CCA-0E492FCDFC7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD50D0A9-F1EA-9983-6CCA-0E492FCDFC7C}.Release|Any CPU.Build.0 = Release|Any CPU
{9ACA5598-D93D-4956-A5BB-9311957301D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9ACA5598-D93D-4956-A5BB-9311957301D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9ACA5598-D93D-4956-A5BB-9311957301D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9ACA5598-D93D-4956-A5BB-9311957301D6}.Release|Any CPU.Build.0 = Release|Any CPU
{CD93A91F-80F1-9232-0D40-5BCB93B297E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD93A91F-80F1-9232-0D40-5BCB93B297E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD93A91F-80F1-9232-0D40-5BCB93B297E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD93A91F-80F1-9232-0D40-5BCB93B297E9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -217,6 +241,10 @@ Global
{7A2873BC-70A1-489B-9609-E9D7D382C826} = {8F8738AD-EBC3-4C24-882B-5D9FAC427E80}
{99ADC0F0-9433-49AD-86FA-34009CD293BA} = {F8ED6752-5ED3-4EA1-89F0-363C40F8D8E0}
{7354577A-699D-4952-B8DF-27CF0FC7F683} = {2EEE3D0D-6457-46D8-B8E8-FA7364942F1F}
{2A302849-3E35-42E5-A9CA-DC14B34476F0} = {2EEE3D0D-6457-46D8-B8E8-FA7364942F1F}
{CD50D0A9-F1EA-9983-6CCA-0E492FCDFC7C} = {2EEE3D0D-6457-46D8-B8E8-FA7364942F1F}
{9ACA5598-D93D-4956-A5BB-9311957301D6} = {2EEE3D0D-6457-46D8-B8E8-FA7364942F1F}
{CD93A91F-80F1-9232-0D40-5BCB93B297E9} = {2EEE3D0D-6457-46D8-B8E8-FA7364942F1F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6AAE7641-B62C-48BA-8FE6-0F819E5B45EF}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Azure.CosmosRepository\Microsoft.Azure.CosmosRepository.csproj" />
<ProjectReference Include="..\AspireApp.ServiceDefaults\AspireApp.ServiceDefaults.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
<PackageReference Include="Swashbuckle.AspNetCore" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright (c) David Pine. All rights reserved.
// Licensed under the MIT License.

global using AspireApp.ApiService;

global using Microsoft.AspNetCore.HttpLogging;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.Azure.CosmosRepository;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
var builder = WebApplication.CreateBuilder(args);

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

builder.AddCosmosRepositoryClient("cosmos-repository");

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

// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
app.UseExceptionHandler();

app.UseSwagger();

if (app.Environment.IsDevelopment())
{
app.UseSwaggerUI();
app.MapOpenApi();
}

app.MapTodoApi();
app.MapDefaultEndpoints();

app.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) David Pine. All rights reserved.
// Licensed under the MIT License.

using Newtonsoft.Json;

namespace AspireApp.ApiService;

/// <summary>
/// Represents a todo item.
/// </summary>
/// <remarks>
/// <example>
/// Consider the following example:
/// <code lang="csharp">
/// Todo todo = "🐕 Walk the dog.";
///
/// // Imagine time passes and you actually walk the dog.
/// // To update the todo, mark it as complete:
///
/// todo.IsCompleted = true;
/// </code>
/// </example>
/// </remarks>
public sealed class Todo : Item
{
/// <summary>
/// Gets or sets the title of the todo.
/// </summary>
[JsonProperty("title")]
public string Title { get; set; } = "";

/// <summary>
/// Gets or sets whether the todo is considered complete.
/// </summary>
[JsonProperty("isCompleted")]
public bool IsCompleted { get; set; }

/// <summary>
/// Implicitly converts the given <see cref="string"/>
/// <paramref name="title"/> to a <see cref="Todo"/>.
/// </summary>
/// <param name="title">The title of the todo.</param>
/// <returns>
/// A new <see cref="Todo"/> instance with the
/// given <paramref name="title"/> as the <see cref="Title"/>.
/// </returns>
public static implicit operator Todo(string title) => new()
{
Title = title,
IsCompleted = false
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) David Pine. All rights reserved.
// Licensed under the MIT License.

namespace AspireApp.ApiService;

public static class TodoEndpointExtensions
{
public static IEndpointRouteBuilder MapTodoApi(this IEndpointRouteBuilder app)
{
var todos = app.MapGroup("/api/todos");

todos.MapGet("", GetTodosAsync)
.WithOpenApi()
.Produces<Todo[]>(200)
.WithHttpLogging(HttpLoggingFields.All);

todos.MapGet("/{id}", GetTodoAsync)
.WithOpenApi()
.Produces<Todo>(200)
.Produces(404)
.WithHttpLogging(HttpLoggingFields.All);

todos.MapPost("", CreateTodoAsync)
.WithOpenApi()
.Produces(201)
.Produces(400)
.WithHttpLogging(HttpLoggingFields.All);

todos.MapPut("", UpdateTodoAsync)
.WithOpenApi()
.Produces(204)
.Produces(404)
.WithHttpLogging(HttpLoggingFields.All);

todos.MapDelete("/{id}", DeleteTodoAsync)
.WithOpenApi()
.Produces(204)
.Produces(404)
.WithHttpLogging(HttpLoggingFields.All);

return app;
}

static IAsyncEnumerable<Todo> GetTodosAsync([FromServices] IReadOnlyRepository<Todo> repository)
=> repository.PageAsync(predicate: todo => todo != null, limit: 1_000, pageSize: 25);

static async Task<IResult> GetTodoAsync([FromRoute] string id, [FromServices] IRepository<Todo> repository)
{
var todo = await repository.GetAsync(id);

return todo is null
? Results.NotFound()
: Results.Json(todo);
}

static async Task<IResult> CreateTodoAsync([FromBody] Todo todo, [FromServices] IRepository<Todo> repository)
{
var result = await repository.CreateAsync(todo);

return result is null
? Results.BadRequest()
: Results.Created($"/api/todos/{result.Id}", result);
}

static async Task<IResult> UpdateTodoAsync([FromBody] Todo inputTodo, [FromServices] IRepository<Todo> repository)
{
await repository.UpdateAsync(inputTodo);

return Results.NoContent();
}

static async Task<IResult> DeleteTodoAsync([FromRoute] string id, [FromServices] IRepository<Todo> repository)
{
await repository.DeleteAsync(id);

return Results.NoContent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

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

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<UserSecretsId>e8bdcee5-71ce-4928-a339-f8dbed60e7db</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\AspireApp.ApiService\AspireApp.ApiService.csproj" />
<ProjectReference Include="..\AspireApp.Web\AspireApp.Web.csproj" />
</ItemGroup>

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

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (cosmosContainer) David Pine. All rights reserved.
// Licensed under the MIT License.

var builder = DistributedApplication.CreateBuilder(args);

var db = builder.AddAzureCosmosDB("cosmos-repository")
.RunAsEmulator(static cosmosContainer =>
cosmosContainer.WithLifetime(ContainerLifetime.Persistent));

var apiService = builder.AddProject<Projects.AspireApp_ApiService>("apiservice")
.WithExternalHttpEndpoints()
.WithReference(db)
.WaitFor(db);

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

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
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 272cc6b

Please sign in to comment.