// warm all the serivces up, can chain these together if needed
services.AddStartupTask<WarmupServicesStartupTask>();
// setup and register boostrapper and it's installers
services.AddBootStrapper<DefaultApplicationBootStrapper>(Configuration, o => {
o.AddInstaller(new IdentityServerInstaller());
o.AddInstaller(new NewtonsoftInstaller());
o.AddInstaller(new SubjectPrincipalInstaller());
o.AddInstaller(new SwaggerInstaller());
o.AddInstaller(new ModelMapperInstaller());
});
// add response compression using gzip and brotli compression
services.AddDefaultResponseCompression(CompressionLevel.Optimal);
var instrumentationKey = Configuration["ApplicationInsights:InstrumentationKey"];
var serviceName = Configuration["Service:Name"];
// add application insights telemetry
services.AddApplicationInsights(serviceName, instrumentationKey);
This contains model classes that are common, i.e:
- PageResult/PagedList - model thow has information about a total resultset as well as the items for a single page of results
- ListResult - model that has results wrapped in common shape, matching PagedResult
// Add the access control using IdentityServer and PolicyServer
services.AddAccessControl(Configuration);
This is the expected shape of settings in appsettings.json:
"IdentityServer": {
"Authority": "http://localhost:5001",
"ApiName": "shoppingcart-api",
"ApiSecret": "apiresource-secret",
"RequireHttpsMetadata": false,
"CacheDuration": "00:10:00",
"CacheEnabled": true,
"Authentication": {
"GrantType": "client_credentials",
"Scope": "catalog-api",
"ClientId": "shoppingcart-service",
"ClientSecret": "secret",
"SlidingExpiration": 30
}
},
"PolicyServer": {
"CacheDuration": "0.00:05:00",
"BasePolicy": "ShoppingCart",
"PolicyServerUrl": "http://localhost:5001",
"BasePolicyPrefix": "ShoppingCart"
},
// Add swagger with versioning and OpenID Connect configuration using Newtonsoft
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var versions = new List<OpenApiInfo> {
new OpenApiInfo {
Version = "v1",
Title = "Acme.ShoppingCart API",
Description = "Acme.ShoppingCart API",
},
new OpenApiInfo {
Version = "v2",
Title = "Acme.ShoppingCart API",
Description = "Acme.ShoppingCart API",
}
};
services.AddSwagger(Configuration, xmlFile, versions);
app.UseSwagger("Acme.ShoppingCart Api", provider);
Note: you may need to add the provider to the Configuration method like this:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
Also make sure that routes include the replacement token for the version number, like this:
[Route("api/v{version:apiVersion}/customers")]
Contains base class AuditableEntity for domain entities as well as Subject domain entity needed by it.
// add SubjectPrincipal for auditing
services.AddSubjectPrincipal();
// intentionally set after UseAuthentication
app.UseMiddleware<SubjectMiddleware>();
Contains the following:
- AuditableDatabaseContext
- UnitOfWorkContext
- IUnitOfWork
- QueryableExtensions for getting paged results
- QueryHintCommandInterceptor
public class DatabaseContext : DbContext {
public DbSet<Person> People { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Tags;Trusted_Connection=True")
.AddInterceptors(new QueryHintCommandInterceptor());
}
}
using (var context = new DatabaseContext()) {
var results = context.People.TagWith("Use option: RECOMPILE").ToList();
}