Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
eaf669f
added cosmosdb sample
bradygaster Jun 13, 2024
9fcea51
Update samples/AspireWithCosmosDb/README.md
bradygaster Jun 14, 2024
9862c1f
updated image per feedback
bradygaster Jun 14, 2024
40eec45
Merge branch 'bradyg/cosmosdb' of https://github.com/dotnet/aspire-sa…
bradygaster Jun 14, 2024
72fa8f9
Update samples/AspireWithCosmosDb/AspireWithCosmos.ApiService/Program.cs
bradygaster Jun 14, 2024
bc8d579
Update samples/AspireWithCosmosDb/AspireWithCosmos.AppHost/AspireWith…
bradygaster Jun 14, 2024
c04b9e3
formatting
bradygaster Jun 14, 2024
d3d82be
Merge branch 'bradyg/cosmosdb' of https://github.com/dotnet/aspire-sa…
bradygaster Jun 14, 2024
1883ca0
more formatting per the ide's suggestions
bradygaster Jun 14, 2024
4637d7e
Update samples/AspireWithCosmosDb/AspireWithCosmos.Web/TodoApiClient.cs
bradygaster Jun 14, 2024
0a0d082
Update samples/AspireWithCosmosDb/AspireWithCosmos.Tests/AspireWithCo…
bradygaster Jun 14, 2024
c909987
Update samples/AspireWithCosmosDb/AspireWithCosmos.ServiceDefaults/As…
bradygaster Jun 14, 2024
4d22886
Update samples/AspireWithCosmosDb/AspireWithCosmos.ServiceDefaults/As…
bradygaster Jun 14, 2024
48a4de5
removed test project per feedback.
bradygaster Jun 14, 2024
f91372c
Merge branch 'bradyg/cosmosdb' of https://github.com/dotnet/aspire-sa…
bradygaster Jun 14, 2024
ec5f76e
simplified terminal image
bradygaster Jun 14, 2024
789446c
added emulator call and comment.
bradygaster Jun 14, 2024
ba4f8bb
added cosmos db to tests
bradygaster Jun 19, 2024
339c7d4
updated an otel lib
bradygaster Jun 21, 2024
c349ac1
one more tweak
bradygaster Jun 21, 2024
1066a07
Bump packages & other tweaks
DamianEdwards Jun 21, 2024
c035293
Add retry policy & health check for Cosmos DB db creation
DamianEdwards Jun 21, 2024
d27bf16
Update samples/AspireWithCosmosDb/AspireWithCosmos.ApiService/AspireW…
bradygaster Jun 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

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

<ItemGroup>
<PackageReference Include="Aspire.Microsoft.Azure.Cosmos" Version="8.0.1" />
<PackageReference Include="NSwag.AspNetCore" Version="14.0.7" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.5" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\AspireWithCosmos.ServiceDefaults\AspireWithCosmos.ServiceDefaults.csproj" />
</ItemGroup>

</Project>
78 changes: 78 additions & 0 deletions samples/AspireWithCosmosDb/AspireWithCosmos.ApiService/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using Microsoft.Azure.Cosmos;

var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();
builder.Services.AddProblemDetails();
builder.Services.AddHostedService<DatabaseBootstrapper>();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApiDocument();
builder.AddAzureCosmosClient("cosmos");

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
app.UseOpenApi();
app.UseSwaggerUi();
}

app.UseExceptionHandler();

// create new todos
app.MapPost("/todos", async (Todo todo, CosmosClient cosmosClient) =>
(await cosmosClient.GetAppDataContainer().CreateItemAsync<Todo>(todo)).Resource
);

// get all the todos
app.MapGet("/todos", (CosmosClient cosmosClient) =>
cosmosClient.GetAppDataContainer().GetItemLinqQueryable<Todo>(allowSynchronousQueryExecution: true).ToList()
);

app.MapPut("/todos/{id}", async (string id, Todo todo, CosmosClient cosmosClient) =>
(await cosmosClient.GetAppDataContainer().ReplaceItemAsync<Todo>(todo, id)).Resource
);

app.MapDelete("/todos/{userId}/{id}", async (string userId, string id, CosmosClient cosmosClient) =>
{
await cosmosClient.GetAppDataContainer().DeleteItemAsync<Todo>(id, new PartitionKey(userId));
return Results.Ok();
});

app.MapDefaultEndpoints();

app.Run();

// The Todo service model used for transmitting data
public record Todo(string Description, string id, string UserId, bool IsComplete = false)
{
// partiion the todos by user id
internal static string UserIdPartitionKey = "/UserId";
}

// Background service used to scaffold the Cosmos DB/Container
public class DatabaseBootstrapper(CosmosClient cosmosClient) : IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
await cosmosClient.CreateDatabaseIfNotExistsAsync("tododb");
var database = cosmosClient.GetDatabase("tododb");
await database.CreateContainerIfNotExistsAsync(new ContainerProperties("todos", Todo.UserIdPartitionKey));
}

public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

// Convenience class for reusing boilerplate code
public static class CosmosClientTodoAppExtensions
{
public static Container GetAppDataContainer(this CosmosClient cosmosClient)
{
var database = cosmosClient.GetDatabase("tododb");
var todos = database.GetContainer("todos");

if(todos == null) throw new ApplicationException("Cosmos DB collection missing.");

return todos;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5535",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7422;http://localhost:5535",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
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,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
</PropertyGroup>

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

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

</Project>
12 changes: 12 additions & 0 deletions samples/AspireWithCosmosDb/AspireWithCosmos.AppHost/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var builder = DistributedApplication.CreateBuilder(args);

var cosmos = builder.AddAzureCosmosDB("cosmos");

var apiService = builder.AddProject<Projects.AspireWithCosmos_ApiService>("apiservice")
.WithReference(cosmos);

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

builder.Build().Run();
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:17097;http://localhost:15184",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21143",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22152"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15184",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19196",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20015"
}
}
}
}
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"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireSharedProject>true</IsAspireSharedProject>
</PropertyGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />

<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.3.0" />
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="8.0.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.8.1" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.8.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.8.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.8.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.8.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;

namespace Microsoft.Extensions.Hosting;

// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
// This project should be referenced by each service project in your solution.
// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
public static class Extensions
{
public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
{
builder.ConfigureOpenTelemetry();

builder.AddDefaultHealthChecks();

builder.Services.AddServiceDiscovery();

builder.Services.ConfigureHttpClientDefaults(http =>
{
// Turn on resilience by default
http.AddStandardResilienceHandler();

// Turn on service discovery by default
http.AddServiceDiscovery();
});

return builder;
}

public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder)
{
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.IncludeScopes = true;
});

builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation();
})
.WithTracing(tracing =>
{
tracing.AddAspNetCoreInstrumentation()
// Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
//.AddGrpcClientInstrumentation()
.AddHttpClientInstrumentation();
});

builder.AddOpenTelemetryExporters();

return builder;
}

private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostApplicationBuilder builder)
{
var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);

if (useOtlpExporter)
{
builder.Services.AddOpenTelemetry().UseOtlpExporter();
}

// Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
//if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
//{
// builder.Services.AddOpenTelemetry()
// .UseAzureMonitor();
//}

return builder;
}

public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder)
{
builder.Services.AddHealthChecks()
// Add a default liveness check to ensure app is responsive
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);

return builder;
}

public static WebApplication MapDefaultEndpoints(this WebApplication app)
{
// Adding health checks endpoints to applications in non-development environments has security implications.
// See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
if (app.Environment.IsDevelopment())
{
// All health checks must pass for app to be considered ready to accept traffic after starting
app.MapHealthChecks("/health");

// Only health checks tagged with the "live" tag must pass for app to be considered alive
app.MapHealthChecks("/alive", new HealthCheckOptions
{
Predicate = r => r.Tags.Contains("live")
});
}

return app;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="8.0.0" />
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\AspireWithCosmos.AppHost\AspireWithCosmos.AppHost.csproj" />
</ItemGroup>

<ItemGroup>
<Using Include="Aspire.Hosting.Testing" />
<Using Include="Xunit" />
</ItemGroup>

</Project>
Loading