Skip to content

Commit

Permalink
Minimal API template enhancements (#289)
Browse files Browse the repository at this point in the history
* Add template symbol to detect Minimal API support

Adds a template symbol that detects if the template is being instantiated for a .NET 7 or higher project.

Also adds .NET 8 as a framework target option since first .NET preview has just been released.

* Add project items to templates project

Adds the .csproj file, Program.cs and README.md for the adapter host template to the templates project. This is to allow templating engine conditional statements to be added to these files.

* Update DataCore.Adapter.Templates.csproj to use some source items from templates project
  • Loading branch information
wazzamatazz committed Feb 24, 2023
1 parent 594eefb commit c638828
Show file tree
Hide file tree
Showing 7 changed files with 241 additions and 124 deletions.
1 change: 0 additions & 1 deletion examples/ExampleHostedAdapter/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

using ExampleHostedAdapter;

using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
Expand Down
8 changes: 4 additions & 4 deletions examples/MinimalApiExample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
))
.AddAdapter(sp => ActivatorUtilities.CreateInstance<WaveGeneratorAdapter>(sp, AdapterId));

#if DEBUG
// Pretty-print JSON responses
builder.Services.Configure<JsonOptions>(options => options.SerializerOptions.WriteIndented = true);
#endif
// Pretty-print JSON responses when running in development mode.
if (builder.Environment.IsDevelopment()) {
builder.Services.Configure<JsonOptions>(options => options.SerializerOptions.WriteIndented = true);
}

builder.Services
.AddDataCoreAdapterApiServices();
Expand Down
147 changes: 28 additions & 119 deletions src/DataCore.Adapter.Templates/DataCore.Adapter.Templates.csproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

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

<ItemGroup>
<PackageReference Include="IntelligentPlant.AppStoreConnect.Adapter" />
<PackageReference Include="IntelligentPlant.AppStoreConnect.Adapter.AspNetCore.Grpc" />
<PackageReference Include="IntelligentPlant.AppStoreConnect.Adapter.AspNetCore.HealthChecks" />
<!--#if (UseMinimalApi) -->
<PackageReference Include="IntelligentPlant.AppStoreConnect.Adapter.AspNetCore.MinimalApi" />
<!--#else -->
<PackageReference Include="IntelligentPlant.AppStoreConnect.Adapter.AspNetCore.Mvc" />
<!--#endif -->
<PackageReference Include="IntelligentPlant.AppStoreConnect.Adapter.AspNetCore.SignalR" />
<PackageReference Include="IntelligentPlant.AppStoreConnect.Adapter.KeyValueStore.Sqlite" />
<PackageReference Include="IntelligentPlant.AppStoreConnect.Adapter.OpenTelemetry" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" />
<PackageReference Include="OpenTelemetry" />
<PackageReference Include="OpenTelemetry.Api" />
<PackageReference Include="OpenTelemetry.Exporter.Console" />
<PackageReference Include="OpenTelemetry.Exporter.Jaeger" />
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
<PackageReference Include="OpenTelemetry.Instrumentation.GrpcNetClient" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
<PackageReference Include="OpenTelemetry.Instrumentation.SqlClient" />
</ItemGroup>

</Project>
166 changes: 166 additions & 0 deletions src/DataCore.Adapter.Templates/src/aschostedadapter/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
using DataCore.Adapter.KeyValueStore.Sqlite;

using ExampleHostedAdapter;

using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

// The [VendorInfo] attribute is used to add vendor information to the adapters in this assembly,
// as well as the host information for the application.
[assembly: DataCore.Adapter.VendorInfo("My Company", "https://my-company.com")]

var builder = WebApplication.CreateBuilder(args);

// Our adapter settings are stored in adaptersettings.json.
builder.Configuration
.AddJsonFile(Constants.AdapterSettingsFilePath, false, true);

builder.Services
.AddLocalization();

#if (UseMinimalApi)
// Allows failed requests to generate RFC 7807 responses.
builder.Services
.AddProblemDetails();
#endif

builder.Services
.AddDataCoreAdapterAspNetCoreServices()
.AddHostInfo(
name: "ASP.NET Core Adapter Host",
description: "ASP.NET Core adapter host for My Adapter"
)
// Add a SQLite-based key-value store service. This can be used by our adapter to persist data
// between restarts.
//
// NuGet packages are also available for other store types, including file system and Microsoft
// FASTER-based stores.
.AddKeyValueStore(sp => {
var path = Path.Combine(AppContext.BaseDirectory, "kvstore.db");
var options = new SqliteKeyValueStoreOptions() {
ConnectionString = $"Data Source={path};Cache=Shared"
};
return ActivatorUtilities.CreateInstance<SqliteKeyValueStore>(sp, options);
})
// Register the adapter options
.AddAdapterOptions<MyAdapterOptions>(
// The adapter will look for an instance of the options with a name that matches its ID.
Constants.AdapterId,
// Bind the adapter options against the application configuration and ensure that they are
// valid at startup.
opts => opts
.Bind(builder.Configuration.GetSection("AppStoreConnect:Adapter:Settings"))
.ValidateDataAnnotations()
.ValidateOnStart()
)
// Register the adapter. We specify the adapter ID as an additional constructor parameter
// since this will not be supplied by the service provider.
.AddAdapter<MyAdapter>(Constants.AdapterId);

#if (UseMinimalApi)
// Register supporting services for Minimal API routes.
builder.Services
.AddDataCoreAdapterApiServices();
#else
// Register adapter MVC controllers.
builder.Services
.AddMvc()
.AddDataCoreAdapterMvc();
#endif

// Register adapter SignalR hub.
builder.Services
.AddSignalR()
.AddDataCoreAdapterSignalR();

// Register adapter gRPC services.
builder.Services
.AddGrpc()
.AddDataCoreAdapterGrpc();

// Register adapter health checks. See https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks
// for more information about ASP.NET Core health checks.
builder.Services
.AddHealthChecks()
.AddAdapterHealthChecks();

// Resource builder for OpenTelemetry trace/metrics export. We will use the adapter ID as the
// OpenTelemetry service instance ID for the host.
var otelResourceBuilder = ResourceBuilder.CreateDefault().AddDataCoreAdapterApiService(Constants.AdapterId);

// Register OpenTelemetry services. This can be safely removed if not required.
builder.Services
.AddOpenTelemetry()
.WithTracing(otel => otel
// Set the resource builder to identify where the traces are coming from.
.SetResourceBuilder(otelResourceBuilder)
// Records incoming HTTP requests made to the adapter host.
.AddAspNetCoreInstrumentation()
// Records outgoing HTTP requests made by the adapter host.
.AddHttpClientInstrumentation()
// Records gRPC client requests made by the adapter host.
.AddGrpcClientInstrumentation()
// Records queries made by System.Data.SqlClient and Microsoft.Data.SqlClient.
.AddSqlClientInstrumentation()
// Records activities created by adapters and adapter hosting packages.
.AddDataCoreAdapterInstrumentation()
// Exports traces to Jaeger (https://www.jaegertracing.io/) using default settings.
.AddJaegerExporter())
.WithMetrics(otel => otel
// Set the resource builder to identify where the metrics are coming from.
.SetResourceBuilder(otelResourceBuilder)
// Observe instrumentation for the .NET runtime.
.AddRuntimeInstrumentation()
// Observe ASP.NET Core instrumentation.
.AddAspNetCoreInstrumentation()
// Observe HTTP client instrumentation.
.AddHttpClientInstrumentation()
// Observe instrumentation generated by the adapter support libraries.
.AddDataCoreAdapterInstrumentation()
// Exports metrics in Prometheus format using default settings. Prometheus metrics are
// served via the scraping endpoint registered below.
.AddPrometheusExporter());

// Build the app and the request pipeline.
var app = builder.Build();

#if (UseMinimalApi)
app.UseExceptionHandler();
app.UseStatusCodePages();
#endif

if (app.Environment.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
else {
// The default HSTS value is 30 days. You may want to change this for production
// scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseRequestLocalization();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

#if (UseMinimalApi)
app.MapDataCoreAdapterApiRoutes();
#else
app.MapControllers();
#endif
app.MapDataCoreAdapterHubs();
app.MapDataCoreGrpcServices();
app.MapHealthChecks("/health");
app.MapPrometheusScrapingEndpoint("/metrics");
app.MapRazorPages();

// Fallback route that redirects to the UI home page
app.MapFallback("/{*url}", context => {
context.Response.Redirect("/");
return Task.CompletedTask;
});

app.Run();
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,19 @@
{
"choice": "net7.0",
"description": ".NET 7.0"
},
{
"choice": "net8.0",
"description": ".NET 8.0"
}
],
"defaultValue": "net6.0",
"replaces": "net6.0"
},
"UseMinimalApi": {
"type": "computed",
"value": "(Framework != \"net6.0\")"
},
"AdapterOptionsName": {
"type": "derived",
"valueSource": "name",
Expand Down

0 comments on commit c638828

Please sign in to comment.