Reading over the documentation for ASP.NET Core, there are two methods singled out for Startup: Configure and ConfigureServices.
Neither of these seemed like a good place to put custom code that I would like to run at startup. Perhaps I want to add a custom field to my DB if it doesn't exist, check for a specific file, seed some data into my database, etc. Code that I want to run once, just at app start.
Is there a preferred/recommended approach for going about doing this?
I agree with the OP.
My scenario is that I want to register a microservice with a service registry but have no way of knowing what the endpoint is until the microservice is running.
I feel that both the Configure and ConfigureServices methods are not ideal because neither were designed to carry out this kind of processing.
Another scenario would be wanting to warm up the caches, which again is something we might want to do.
There are several alternatives to the accepted answer:
Create another application which carries out the updates outside of your website, such as a deployment tool, which applies the database updates programmatically before starting the website
In your Startup class, use a static constructor to ensure the website is ready to be started
Update
The best thing to do in my opinion is to use the IApplicationLifetime interface like so:
public class Startup
{
public void Configure(IApplicationLifetime lifetime)
{
lifetime.ApplicationStarted.Register(OnApplicationStarted);
}
public void OnApplicationStarted()
{
// Carry out your initialisation.
}
}
This can be done by creating an IHostedService implementation and registering it using IServiceCollection.AddHostedService<>() in ConfigureServices() in your startup class.
Example
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
public class MyInitializer : IHostedService
{
public Task StartAsync(CancellationToken cancellationToken)
{
// Do your startup work here
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
// We have to implement this method too, because it is in the interface
return Task.CompletedTask;
}
}
using Microsoft.Extensions.DependencyInjection;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHostedService<MyInitializer>();
}
}
Notes
The main application will not be started until after your code has finished executing.
Constructor dependency injection is available to the IHostedService implementation.
I can recommend this blog post for more info, and an example of how to use async: https://andrewlock.net/running-async-tasks-on-app-startup-in-asp-net-core-3/
For more background reading, see this discussion: https://github.com/dotnet/aspnetcore/issues/10137
Basically there are two entry points for such custom code at startup time.
1.) Main method
As a ASP.NET Core application has got the good old Main method as entry point you could place code before the ASP.NET Core startup stuff, like
public class Program
{
public static void Main(string[] args)
{
// call custom startup logic here
AppInitializer.Startup();
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
2.) Use your Startup class
As you already stated in your question is the Configure and ConfigureServices a good place for your custom code.
I would prefer the Startup class. From the runtime perspective it does not matter, if the call is called in startup or somewhere else before the host.Run() call. But from a programmer's point of view who is accustomed to the ASP.NET framework then his first look for such logic would be the Startup.cs file. All samples and templates put there the logic for Identity, Entity Framework initialization and so on. So as a convention I recommend to place the initialization stuff there.
Related
I've got a .net API and my Program.cs has started to become quite bloated with the following:
.
.
.
//core mappers
builder.Services.AddSingleton<IAppData_Mapper, AppData_Mapper>();
builder.Services.AddSingleton<IUserData_Mapper, UserData_Mapper>();
//pylon export services
builder.Services.AddTransient<IPylonItemExportService, PylonItemExportService>();
builder.Services.AddTransient<IPylonContactExportService, PylonContactExportService>();
//pylon repositories
builder.Services.AddSingleton<IPylonContactRepository, PylonContactRepository>();
builder.Services.AddSingleton<IPylonConnectionRepository, PylonConnectionRepository>();
builder.Services.AddSingleton<IPylonItemRepository, PylonItemRepository>();
builder.Services.AddSingleton<IPylonContactExportRepository, PylonContactExportRepository>();
builder.Services.AddSingleton<IPylonItemExportRepository, PylonItemExportRepository>();
builder.Services.AddSingleton<IPylonDocumentRepository, PylonDocumentRepository>();
builder.Services.AddSingleton<IPylonCentLineRepository, PylonCentLineRepository>();
builder.Services.AddSingleton<IPylonComEntryRepository, PylonComEntryRepository>();
builder.Services.AddSingleton<IPylonSupplierRepository, PylonSupplierRepository>();
builder.Services.AddSingleton<IPylonCustomerRepository, PylonCustomerRepository>();
//pylon sync services
builder.Services.AddTransient<IPylonItemSyncService, PylonItemSyncService>();
builder.Services.AddTransient<IPylonContactSyncService, PylonContactSyncService>();
builder.Services.AddTransient<IPylonMeasurementunitSyncService, PylonMeasurementunitSyncService>();
builder.Services.AddTransient<IPylonDocEntrySyncService, PylonDocEntrySyncService>();
builder.Services.AddTransient<IPylonCentLineSyncService, PylonCentLineSyncService>();
builder.Services.AddTransient<IPylonCommEntrySyncService, PylonCommEntrySyncService>();
builder.Services.AddTransient<IPylonCustomerSyncService, PylonCustomerSyncService>();
builder.Services.AddTransient<IPylonSupplierSyncService, PylonSupplierSyncService>();
.
.
.
What would be the optimal way to move these outside of my program.cs? Ideally i'd like for them to be in a seperate class that will be called via the Program.cs
Can I pass the builder to a static method that will add the services?
Can I create the array of services and do something like Services.AddRange?
I'm fairly new to the DI architecture on .net and any guidelines would be grately appreciated!
To answer your first question you can move the service registration to another class by creating a new class and having the method take in the builder and register services then return or create an extension method. Creating an extension method is slightly "neater" and you can do it like so.
public static class MyServiceExtension
{
public static IServiceCollection AddMyServices(this IServiceCollection services)
{
// add your services
return services;
}
}
Now in your Program.cs all you'll do is.
builder.Services.AddMyServices();
I want to implement AOP for the logging in my .NET Core 2.1 solution. I've never used it before and I've been looking online and cant seem to see any examples of people using it with Core 2. Does anyone know how i would go about this?
For example what packages to use for AOP and have any example code to get me started? Im using the built in DI with .net core so i dont need to worry about that part.
Microsoft DI does not offer advances scenarios such as interceptor or decorators(there is a workaround for decorators using Microsoft DI: https://medium.com/#willie.tetlow/net-core-dependency-injection-decorator-workaround-664cd3ec1246).
You can implement AOP by using Autofac (https://autofaccn.readthedocs.io/en/latest/advanced/interceptors.html) or Simple injector with dynamic proxy. Both have a really good documentation. Simple injector doesn't have an out of the box solution for interception because of their design rules but you can add an extension for it (http://simpleinjector.readthedocs.io/en/latest/aop.html).
Here is a basic AOP scenario from the official SI documentation:(http://simpleinjector.readthedocs.io/en/latest/InterceptionExtensions.html) :
//Add registration to the composition root
container.InterceptWith<MonitoringInterceptor>(serviceType => serviceType.Name.EndsWith("Repository"));`
// Here is an example of an interceptor implementation.
// NOTE: Interceptors must implement the IInterceptor interface:
private class MonitoringInterceptor : IInterceptor {
private readonly ILogger logger;
public MonitoringInterceptor(ILogger logger) {
this.logger = logger;
}
public void Intercept(IInvocation invocation) {
var watch = Stopwatch.StartNew();
// Calls the decorated instance.
invocation.Proceed();
var decoratedType = invocation.InvocationTarget.GetType();
this.logger.Log(string.Format("{0} executed in {1} ms.",
decoratedType.Name, watch.ElapsedMilliseconds));
}
}
Disclaimer: I am the producer of this solution
Microsoft does not provide an AOP solution out the box for Net Core. However, I have produced a 3rd party project which may help. It works directly with Net Core and plugs in via the ServiceCollection registration in your application.
What Microsoft does provide is a library called System.Runtime.DispatchProxy which can be used to create proxy objects for your classes. However, this proxy isnt particularly useful or feature rich on its own and would require a lot of extra code to get something that is on a level with Castle Proxy (the well known Dynamic Proxy library)
With that in mind, I have created a library which wraps the DispatchProxy into code that can be easily injected during the ServiceCollection configuration in the application startup. The trick is to have a way to create attributes AND a paired interceptor that can be applied to your methods. The attribute is then read during the Proxy wrapping and the relevant Interceptor is called.
This is an example Interceptor Attribute
public class ConsoleLogAttribute : MethodInterceptorAttribute
{
}
This is an example Interceptor class
public class ConsoleLogInterceptor : MethodInterceptor
{
public override void BeforeInvoke(IInterceptionContext interceptionContext)
{
Console.WriteLine($"Method executing: {interceptionContext.CurrentMethod.Name}");
}
public override void AfterInvoke(IInterceptionContext interceptionContext, object methodResult)
{
Console.WriteLine($"Method executed: {interceptionContext.CurrentMethod.Name}");
}
}
This is how it would be applied to your method
[ConsoleLog]
public void TestMethod()
{
}
And then finally, this is how it would be added to your ServiceCollection configuration (assuming that the class you wanted to Proxy was called [TestClass]:
public void ConfigureServices(IServiceCollection services)
{
// Configure Simple Proxy
services.EnableSimpleProxy(p => p.AddInterceptor<ConsoleLogAttribute, ConsoleLogInterceptor>());
// Configure your services using the Extension Methods
services.AddTransientWithProxy<ITestClass, TestClass>();
}
Take a look at this GitHub project: https://github.com/f135ta/SimpleProxy
I have a bunch of already written middlewares. As i know they can easily be used at global pipeline level.
[assembly: OwinStartup(typeof(Startup))]
namespace Portal.Web
{
public class Startup
{
public void Configuration(IAppBuilder builder)
{
builder
.UseApiResponseCompression()
....
}
}
}
But i really excited hypothetical opportunities to use this middleware in appropriate controller or method ( I've seen such functionality implementation in asp.net core)
Q: Is it possible to use arbitrary middleware in specific controller or ever method ( like filters) in asp.net web api2?
Will MiddlewareFilter do what you are expecting?
You create a pipeline class, say MyPipeline, which has one method with signature public void Configure(IApplicationBuilder applicationBuilder). Then place [MiddlewareFilter(typeof(MyPipeline))] on the controller or action.
I am trying to test my ASP.NET Core Web Application with Microsoft.AspNetCore.TestHost. It works fine this way (result has status 200):
var server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
var client = server.CreateClient();
var result = await client.GetAsync(someRequestUrl);
In this case the real Startup class from the API project is used.
However, I don't want to use the real Startup class in my integration test. The main reason is the need to mock some stuff that gets wired during application startup. For example, the database server to be used. It can be done in a very elegant way by defining a virtual method in Startup.cs:
public virtual void SetupDbContext(IServiceCollection services)
{
services.AddDbContext<TbsDb>(options =>
options.UseSqlServer("someConnectionString"));
}
Then I create a new class, which inherits from the original Startup class and overrides this method to use Sqlite, in-memory database or whatever:
public override void SetupDbContext(IServiceCollection services)
{
services.AddDbContext<TbsDb>(
options => options.UseSqlite("someConnectionString"));
}
This also works well with TestHost if the new class is in the same API project.
Obviously, I don't want this class which is used for testing to be there. But if I move it to integration tests project and create a TestServer there, the same test fails because the result has status 404. Why is it happening? It still inherits from the Startup class, which is in the API project. Thus I expect all the routes to work the same no matter where the TestStartup class is. Can it be solved somehow?
I am building a support library for ASP.NET Core websites. I have a few pieces of middleware that need to be enabled, and they need to be added before any other middleware due what they do.
I can create an extension method on IWebHostBuilder to add services, likewise for configuring logging, but I don't see any way to add middleware in a programmatic way. Is there any way to do this? Looking at the source for WebHost/WebHostBuilder nothing jumped out.
Given the first comment, I may not have been clear enough. I know how to create middleware and use it. What I am trying to do is ensure that when the Configure(IApplicationBuilder app) method is called on Startup by the framework, my middleware is already in place. In a similar manner to being able to do ServiceConfiguration prior to Startup even being created. So an extension method like
public static IWebHostBuilder AddPayscaleHostingServices(this IWebHostBuilder webHostBuilder, string serviceName)
{
return webHostBuilder.ConfigureServices(collection =>
{
collection.RegisterPayscaleHostingServices();
}).ConfigureLogging(factory =>
{
});
}
gives me the ability to do some setup prior to the webHostBuilder.Build method, but I don't see anything similar for middleware/anything on IApplicationBuilder.
Thanks,
Erick
You could use a startup filter to achieve this. Startup filters allow you to configure middleware from a service resolved from the DI container.
Defining a startup filter is easy:
public class MyStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return app =>
{
// Configure middleware
// ...
// Call the next configure method
next(app);
};
}
}
Always make sure to call next(app) or any other middleware won't be configured.
Now register the startup filter as a singleton implementation of IStartupFilter in your ConfigureServices method:
services.AddSingleton<IStartupFilter, MyStartupFilter>();