UgenTec.WebApi QuickStart
The UgenTec.WebApi
Block contains all Ugentec opinionated logic to host a AspNetCore project. Start with a new ASP.NET Core 2.2 project.
Installation
Use the internal Ugentec Nuget-2 feed to install the UgenTec.WebApi library
install-package UgenTec.WebApi
Configuration
By convention UgenTec products will not use appsettings.json files. All environment dependent parameters should be set using environment variables.
To configure your local development setup wit UgenTec defaults add following settings to the launchSettings.json file of your startup process. (Make sure to add the section to all hosting profiles in case multiple profiles are used (eg. IISExpress, local IIS, console hosting, ...))
Specifically for the environment variable MAPPEDVOLUME
, there is a MAPPEDVOLUMELOCALOVERRIDE
(to be configured on system level) available must there be a need.
{
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"RELEASERINGITERATION": "<<YOUR RELEASE RING ITERATION HERE>>",
"COMPONENTNAME": "<<YOUR APPLICATIONNAME HERE>>",
"MAPPEDVOLUME": "C:\\UgenTec\\<<YOUR APPLICATIONNAME HERE>>",
"LOGGING__LOGLEVEL__DEFAULT": "Warning",
"ALLOWEDHOSTS": "*",
"APPINSIGHTS__CONNECTIONSTRING": "InstrumentationKey=DummyKeyForDevelopment",
"AUTHENTICATION__IDENTITYSERVICEURL": "http://localhost:8081",
"AUTHENTICATION__IDENTITYSERVICECLIENTID": "FastTyperAPIId",
"AUTHENTICATION__IDENTITYSERVICECLIENTSECRET": "11111111-1111-1111-1111-111111111111",
"AUTHENTICATION__APINAME": "FastTyperAPI",
"AUTHENTICATION__APISECRET": "11111111-1111-1111-1111-111111111111"
"CORS__ALLOWEDORIGINS": "http://localhost:4200"
}
}
Logging levels can be overriden by adding additional environment variables :
{
"LOGGING__LOGLEVEL__DEFAULT": "Debug",
"LOGGING__LOGLEVEL__OVERRIDE__Microsoft": "Trace",
"LOGGING__LOGLEVEL__OVERRIDE__Microsoft.EntityFrameworkCore.Database.Command": "Information",
}
Note that the namespaces used when overriding loglevels are case sensitive.
Program.cs : Configure UgenTec web hosting defaults
UseUgenTecDefaultSetup
should be called in Program.CreateWebHostBuilder(). This will automatically configure:
- Logging with Serilog (to File, Console and Application Insights)
- Hosting in Kestrel
Example
using Microsoft.Extensions.Hosting;
namespace UgenTec.WebApi.TestHost
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseUgenTecDefaultWebAPISetup<Startup>();
}
}
Startup.cs: Configure UgenTec default application services and application pipeline
UgenTecWebApiOptions
The UgenTecWebApiOptions class is used for adding application specific logic to the UgenTec defaults. As these options are passed in to a number of UgenTec extension methods it makes sense to define them at the top of the startup class, so it's easy to find them for reference.
For a detailed view of the available options refer to the API documentation of the UgenTecWebApiOptions
class.
Minimal Setup:
public class Startup
{
private readonly UgenTecWebApiOptions _ugenTecWebApiOptions;
//The UgenTecWebApiOptions configuration is used by multiple extension methods in the startup phase,
//For that reason it makes more sense to keep it stored in a field.
public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironment)
{
_ugenTecWebApiOptions = new UgenTecWebApiOptions()
{
ApplicationInsightsConnectionString = configuration["AppInsights:ConnectionString"],
ApplicationName = "<<YOUR APPLICATION NAME HERE>>",
ApplicationVersion = FileVersionInfo.GetVersionInfo(typeof(Startup).Assembly.Location).ProductVersion,
IsDevelopment = hostingEnvironment.IsDevelopment(),
AuthenticationOptions =
{
Authority = configuration["Authentication:IdentityServiceURL"],
ApiName = configuration["Authentication:ApiName"],
ApiSecret = configuration["Authentication:ApiSecret"],
DefaultScopes = new List<string>() { "Scope1", "Scope2" }
//Add all scopes which should have access to all endpoints that have no overruling authorization policy defined.
//Users will be authorized if they have at least one of the scopes defined here.
},
ExceptionMappings = builder =>
{
builder.MapException<ArgumentOutOfRangeException>(e =>
(StatusCodes.Status400BadRequest,
new ErrorDetails() { Message = e.Message }));
}
};
}
Defining allowed CORS origins :
_ugenTecWebApiOptions = new UgenTecWebApiOptions()
{
//... mimimal setup ...
CorsConfiguration = CorsConfigurations.UgenTecDefaultCorsConfiguration(
configuration["Cors:AllowedOrigins"].Split(",",StringSplitOptions.RemoveEmptyEntries))
}
Defining extra exception mappings :
UgenTec WebApi block adds middleware to the application pipeline to translate specific exceptions to http responses and statuscodes. To add application specific mappings include following statement on UgenTecWebAPIOptions()
_ugenTecWebApiOptions = new UgenTecWebApiOptions()
{
//... mimimal setup ...
ExceptionMappings = builder =>
{
builder.MapException<ArgumentOutOfRangeException>(e => (
StatusCodes.Status400BadRequest,
new ErrorDetails() { Message = e.Message }));
}
}
Configuring authentication options for SignalR :
Assuming that signalR routes are mapped to /signalr/... , we allow that accesstokens be passed via url on all paths matching the /signalr segment.
_ugenTecWebApiOptions = new UgenTecWebApiOptions()
{
//... mimimal setup ...
AuthenticationOptions =
{
///... minimal setup ...
UrlSegmentsAllowingAccessTokensInQueryString = {"/signalr"}
},
CorsConfiguration = CorsConfigurations.UgenTecDefaultCorsConfigurationWithSignalRSupport(
configuration["Cors:AllowedOrigins"]
.Split(",",StringSplitOptions.RemoveEmptyEntries)
)
}
To allow tokens to be passed in all urls for the application use UrlSegmentConstants.AnyUrl
;
Adding authorization policy for the /migrate and /migrationstatus endpoints :
All applications using the UgenTec.WebAPI block, will automatically get a /migrate endpoint which UgenTec Central Admin calls in order to trigger database migrations.
This endpoint has a specific authorization policy requirement.
The scope that the admin service uses to call this endpoint is application specific, so the policy needs to be configured explicitly for every application.
We do this by using the AdditionalAuthorizationPolicies
property of the UgentecWebApiOptions
.
_ugenTecWebApiOptions = new UgenTecWebApiOptions()
{
//... mimimal setup ...
AuthenticationOptions =
{
//... minimal setup ...
AdditionalAuthorizationPolicies =
{
{
TenantMigrationController.AuthorizationPolicy, b=>b.RequireScope(<<specific admin service scope>>)
}
}
},
}
Configuring Application Insights behavior
UgenTec.WebApi UseUgenTecDefaults() configures every application with UgenTec biased Application Insights settings. These defaults include :
- Disable Performance Counter Telemetry collection
- Disable Adaptive Sampling
- Disable inclusion of SQL command text in SQL Dependency Telemetry
- Perform biased filtering on Azure Storage SDK and Azure ServiceBus SDK Dependency Telemetry so Telemetry that is not considered useful is not pushed to Application Insight to optimize cost.
The UgenTecWebApiOptions
offers a number of properties for applications or environments that explicitly want to overrule these defaults.
Controlling Performance Counter Telemetry collection in Application Insights :
The Application Insights SDK by default collects basic Performance Counter telemetry for running applications. This includes CPU and Memory usage performance counters. However, as we host all of our applications in Kubernetes, resource consumption is mostly checked at container / node level in Log Analytics and not on application level in Application Insights.
For this reason the collection of this performance counter telemetry is disabled by default starting with FW Core 14.1.0.
Collection of the performance counters can be enabled through the UgenTecWebApiOptions.ApplicationInsightsEnablePerformanceCounterCollection
property.
To enable configuring this behaviour through environment variables, add following statement to the default startup.cs :
_ugenTecWebApiOptions = new UgenTecWebApiOptions()
{
//... mimimal setup ...,
ApplicationInsightsEnablePerformanceCounterCollection = configuration.GetValue<bool>("AppInsights:EnablePerformanceCounterCollection"),
}
And configure the behavior by adding a new environment variable to launchsettings.json and/or DockerFile and Kubernetes yml
"APPINSIGHTS__ENABLEPERFORMANCECOUNTERCOLLECTION": "true"
Controlling Dependency Telemetry Filtering
The Azure.Storage.* and Azure.ServiceBus SDKs emit a large number of DependencyTelemetry items that are considered of little use for purposes that UgenTec uses Application Insight for. This telemetry represent an overhead in costs for Log Analytics, so by default this telemetry is suppressed as a way to reduce costs.
To disable this default filtering through environment variables, add following statement to the default startup.cs :
_ugenTecWebApiOptions = new UgenTecWebApiOptions()
{
//... mimimal setup ...,
ApplicationInsightsDisableDefaultDependencyTelemetryFiltering = configuration.GetValue<bool>("AppInsights:DisableDefaultDependencyTelemetryFiltering")
}
And configure the behavior by adding a new environment variable to launchsettings.json and/or DockerFile and Kubernetes yml
"APPINSIGHTS__DISABLEDEFAULTDEPENDENCYTELEMETRYFILTERING": "true"
Controlling Adaptive Sampling
In the Azure ApplicationInsights SDK adaptive sampling is enabled by default (see https://learn.microsoft.com/en-us/azure/azure-monitor/app/sampling?tabs=net-core-new#adaptive-sampling). UgenTec.WebApi by default disables this behavior so all possible telemetry is captured for support purposes.
To revert back to the adaptive sampling default setting of the ApplicationInsights SDK, add following statement to the default startup.cs :
_ugenTecWebApiOptions = new UgenTecWebApiOptions()
{
//... mimimal setup ...,
ApplicationInsightsEnableAdaptiveSampling = configuration.GetValue<bool>("AppInsights:EnableAdaptiveSampling")
}
And configure the behavior by adding a new environment variable to launchsettings.json and/or DockerFile and Kubernetes yml
"APPINSIGHTS__ENABLEADAPTIVESAMPLING": "true"
Controlling inclusion of SQL Command Text in SQL Dependency Telemetry
The Azure ApplicationInsights SDK by default does not include SQL Command information in SQL Dependency Telemetry. UgenTec.WebApi by default leaves this behavior as is to reduce the size and thus cost of tracked telemetry data.
To enable inclusion of the SQL Command text information in SQL Dependency Telemetry :
_ugenTecWebApiOptions = new UgenTecWebApiOptions()
{
//... mimimal setup ...,
ApplicationInsightsEnableSqlCommandLoggingInDependencyTelemetry = configuration.GetValue<bool>("AppInsights:EnableSqlCommandLoggingInDependencyTelemetry")
}
And configure the behavior by adding a new environment variable to launchsettings.json and/or DockerFile and Kubernetes yml
"APPINSIGHTS__ENABlESQLCOMMANDLOGGINGINDEPENDENCYTELEMETRY": "true"
ServiceCollectionExtensions.AddUgenTecDefaults
AddUgenTecDefaults
should be called in Startup.ConfigureServices()
.
Configuration options can be set.
Calling this method will automatically configures services for:
- HSTS header on all responses
- MVC applying the provided through the mvcOptionsCallback parameter.
- CORS allowing origins defined in CorsOrigins
- Response compression over Https
- Bearer token authentication using authority configured through Authority and with API credentials in ApiName and ApiSecret
- Default authorization policy, restricting access globally to only authenticated users which have access to at least one of the scopes defined in DefaultScopes
- Configures application insights in case a ApplicationInsightsInstrumentationKey is given. (Also registers the MarkRequestAsSuccessTelemetryProcessor and the optional AppInsightsTelemetryInitializer passed in as telemetryInitializerType. If no telemetryInitializerTypeis passed in, the default AppInsightsTelemetryInitializer is registered.)
- Swagger, but only in development mode (available at /swagger endpoint)
- A default HttpContextPrincipalAccessor
Minimal Setup
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddUgenTecDefaults(_ugenTecWebApiOptions);
}
}
Providing additional MVC configuration options
For taking more fine-grained control over the configuration of asp.net MVC core following overload is available :
public void ConfigureServices(IServiceCollection services)
{
services.AddUgenTecDefaults(
_ugenTecWebApiOptions,
mvcOptions =>
{
mvcOptions.Filters.Add(...);
mvcOptions.OutputFormatters.Add(...);
}
}
ApplicationBuilderExtensions.AddUgenTecDefaults
UseUgenTecDefaults
should be called in Startup.Configure()
. It will automatically configure:
- Https redirection (only when not in development mode)
- Hsts (only when not in development mode)
- Request compression
- Response compression
- CORS
- Maps UgenTec defined set of exceptions to http status codes using the ASP.NET Core:
- UnauthorizedException-> 401
- ForbiddenException-> 403
- ApplicationVersionMismatchException-> 412
- ObjectNotFoundException-> 404 with additional TranslatableErrorDetails
- InputValidationException-> 481 with additional ValidationErrorDetails
- DomainValidationException-> 482 with additional ValidationErrorDetails
- Application version check (if client passes UT-Application-Version in header)
- OIDC Authentication
- MVC
- Swagger (only in development mode)
- DeveloperExceptionPage (only in development mode)
Minimal setup
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseUgenTecDefaults(_ugenTecWebApiOptions);
}