DI in .NET Core without ASP.NET Core - dependency-injection

I'm looking to write a daemon process using .NET Core which will basically act much like a cron job and just orchestrate API/DB calls on some interval. As such, it has no need to expose any web routes, so there's no need for ASP.NET Core.
However, afaik ASP.NET Core is where you get that nice Startup class with all the DI plumbing and environment-based configuration you might need.
The way I see it, I have two options:
Forgo ASP.NET Core and just hook up the DI framework on my own. If I go that route, how do I do that?
Include ASP.NET Core just for the DI portion, but then how do I spawn background tasks which "run forever" outside of any request context? My understanding is that the DI framework very much assumes there's some sort of incoming request to orchestrate all the injections.

You seem to pose multiple questions let me try to answer them one by one.
Dependendency injection without Startup Class.
This is definitely possible. Since the Startup class is part of the WebHostBuilder package (which contains Kestrel/webserver). The Dependency injection is nuget package is just a dependency on this package and so can be used alone in the following way:
var services = new ServiceCollection();
services.AddTransient<IMyInterface, MyClass>();
var serviceProvider = services.BuildServiceProvider(); //ioc container
serviceProvider.GetService<IMyInterface>();
So at your program main (startup function) you can add this code and maybe even make the ServiceProvider Staticaly available.
Note that the IHostingEnvironment is also part of the kestrel package and not available to you, but there are simple workarounds for this.
Registration
Im not sure what exactly you mean by spawning background tasks/running forever. But in dotnet you can spawn tasks with TaskCreationOptions.LongRunning to tell the schedular that your task will be running very long and dotnet wel optimise threads for this. you can also use serviceProvider in these tasks.
The only downside to the DI is that you need to set it up at the startup of your application and cannot add new services while running your application (actually you can add to services and then rebuild the serviceProvider, but its easier using another external IOC container). If you where thinking of running some kind of plugin system where dependencies would automaticaly be registered, you're better of making your own factory method.
Also note when using plugins, when they are loaded in as dll's, they cannot be unloaded so if you have a theoretically unlimited amount of plugins, your memory will slowly build up every time you add new plugins.

As of.NET Core 2.1 this can/should be done with a Generic Host. From
.NET Core docs:
"The goal of the Generic Host is to decouple the HTTP pipeline from the Web Host API to enable a wider array of host scenarios..."
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.1
public static async Task Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
.ConfigureServices((hostContext, services) =>
{
// ...
});
await builder.RunConsoleAsync();
}

Related

ServiceStack: container.AutoWire(this) gives a NullReferenceException

If I in my AppHostBase descendant (web api project ) use container.AutoWire(this), it will result in a NullReferenceException in the ServiceStack code, if I am using a web project, thus starting it with the CreateHostBuilder(args).Build().Run(); in the main method.
The error is reproduced in this Github project: https://github.com/tedekeroth/ServiceStackAutoWireTest
The error occurs in AppHostBase.Netcore.Cs, line 158:
If I remove the container.AutoWire(this); in TestAppHost.cs, the error goes away, but then the dependency injection does not work, meaning the Logger in TestAppHostproperty is not assigned:
I am not sure why this happens or what I can do about it. I'd appreciate some input, thanks.
Setup
Visual Studio 2019
Target framework: .NET 5.0 (Console Application)
Project SDK: Microsoft.NET.Sdk.Web
ServiceStack 5.11.0
The IOC AutoWire API attempts to autowire all public property dependencies of an object which is definitely something you should never attempt to do with the AppHost which encapsulates the configuration and behavior of your ServiceStack App where indiscriminatingly overriding every public property is going to leave it in a corrupted state.
Registering your AppHost in the IOC shouldn't be necessary as it's available everywhere via the HostContext.AppHost singleton. It's also a bad idea trying to reference any type defined in your Host Project, (the AppHost being the canonical example) since it creates a circular reference to your Host project in your App logic dependencies which shouldn't have any references back to its Host project, your Host project is supposed to reference all your projects .dll's, configure your App's and all its dependencies, not the other way around.
Should you need access to any Plugins it's recommended to use the GetPlugin<T>() API in your Service for optional plugins or AssertPlugin<T>() for required plugins. If you need to resolve any deps manually you can use TryResolve<T>() API in your Service class. For any of your App's custom config I'd recommend registering them in a custom AppConfig class for your Services to access like any other dependencies.
Otherwise if you really need access to the AppHost you can use the HostContext.AppHost singleton. If you absolutely need to have the AppHost in the IOC, just register it as a normal singleton, i.e. don't try to autowire it:
container.Register<IAppHost>(c => this);
However as mentioned earlier I'd strongly advise against it, have everything your App needs in a custom class (e.g. AppConfig) that is accessed like a normal dependency.

Does Docker have the ability to run background tasks like Azure Webjobs?

I've got a sorta-legacy R&D app which is a monolith website and then a few webjobs which are used for some background processing.
Now, I've been experimenting moving all of this over to Docker + Microservices (note: not because Microservices are the 'new hot stuff' but because our application suits getting split up into more manageable pieces/services.)
It was easy slicing the website up into Gateway API (or BFF Api's) + microservices. But I'm not sure how to handle the webjob migration. The webjobs are (currently) Azure Queue timer and trigger based.
Everything is running under:
- Docker (on linux containers)
- ASP.NET Core 2.1
Anyone have any suggestions what other ways I can migrate the WebJobs to a Docker container of something?
I know Hangfire is a tool that enables background processing on an ASP.NET website. But before I go down that route, just checking if there are other solutions people use.
Also, .NET Core 2.1 has the concept of an IHostedService ... so I'm not sure if this is a legit solution and if so .. how?
You can now run Azure Webjobs in a container.
If you target .Net Core and use Azure WebJobs SDK > 3.0 (Which is distributed as a .Net Standard 2.0 library), you can run the code inside a container. Use an image based on microsoft/dotnet
Here is an example in github: christopheranderson/webjobs-docker-sample
Another option: Implement background tasks in microservices with IHostedService and the BackgroundService class.
This is for .NET Core 2.1
Doesn't require a website (e.g. Kestrel on ASP.NET Core)
Is basically a console app with some smarts to handle the lifecycle of your-tasks/your-services.
Possible clean replacement for webjobs/functions.
Generic Host Code samples
e.g a really basic code example:
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace GenericHostSample
{
public class ProgramHelloWorld
{
public static async Task Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<MyServiceA>();
services.AddHostedService<MyServiceB>();
});
await builder.RunConsoleAsync();
}
}
}

How to inject 3rd party IOC container into ASP.NET Core Startup class

I'm creating a web API using ASP.NET Core, and I'm using SimpleInjector as my DI framework. I understand the basics of how to use SI with ASP.NET Core; my problem is more an architectural one.
I have a project with integration tests for the API project, in order to test the raw API endpoints and responses. Naturally, the test server (set up using Microsoft.AspNetCore.TestHost) should use the API project's real Startup class.
The problem lies in where to register mocks for the controllers' dependencies, because I don't want to have all the production implementations being registered when testing: Firstly, most of them are, of course, dependencies used by the production implementations of the controller dependencies I'll be mocking in the first place; and secondly, in case I update my controllers and forget to register mocks of the new dependencies, I want my code to fail (container verification) instead of silently using production dependencies that are present in the container.
Thus, the dependencies can't be registered in the Startup class. That's fine by me – I think I'd rather keep the composition root in a separate assembly referencing all other assemblies, anyway. AFAICS the ASP.NET Core project would need to reference this project, which exposes a single method that returns a pre-registered container that can be used in the Startup class, where it's needed to register e.g. the controller activator (and will undergo final validation).
But this begs the question: How to get the container – being already registered with all my application components (whether production implementations from the composition root project, or mocks from the integration test project) – into my Startup class?
My initial solution is to simply have a static property on the Startup class called e.g. Container, and assign that before using WebHostBuilder. This seems "pragmatically robust": The application will fail fast (NullReferenceException) if it's not set before the Startup class is run, and the property is only used during setup, so I don't really need to guard against it being set multiple times or being set to null or any such thing – if it's assigned before startup, it works, if not, it won't start.
Does this seem like a solid solution, or am I oblivious to any obvious ways this will will come back to bite me later on? Are there any better solutions?

Accessing dependencies in separate thread in MVC application using Castle Windsor

Working on an MVC application with the below architecture. Bootstrapped with Castle Windsor.
Controller -> Service -> Repository (uses DbContext).
Now certain flows in the application require that I run some part of the flow in a thread.
For example:
Controller -> service ->Repo1 -> control returns to service -> new
Thread() started-> Repo2
The issue I face is the dbcontext is disposed as it is declared as LifestylePerWebRequest().I have tried using LifestyleTransient() that didnt seem to work. What am I missing?
There are similar dependencies which i have to sometimes use in a separate thread and sometimes in a single request. How do i configure Windsor to handle these dependencies?
There is a nuget package that i use to extend the lifestyles for Castle Windsor and it is called: Castle.Windsor.Lifestyles.
It has hybrid lifestyles which are handy for web requests and threads.
container.Register
(
Classes.FromAssemblyContaining<IServiceFactory>()
.BasedOn<IServiceFactory>()
.WithServiceAllInterfaces()
.Configure(c => c.LifeStyle.HybridPerWebRequestPerThread())
);
The important functionality is HybridPerWebRequestPerThread() which creates a new instance for the initial web request and then for every new thread it will create a new instance.

What is the purpose of IApplicationBuilder.New()

In the new ASP.NET 5.0 (vNext), the startup code relies on the IApplicationBuilder interface. The Use method is used to add a handler to the builder, while Build is used to construct the final delegate. But I can't figure out what is the purpose of New. I've been digging in GitHub, but can't find any place where that's used.
Anyone understand what is the purpose of that method?
New() creates a second ApplicationBuilder, sharing all the ApplicationServices and ServerFeatures of the first one, but none of the middleware. It is used internally by the branching extensions (Map, MapWhen, UseWhen) to create the new 'branch'.
You can find the implementation here: ApplicationBuilder.cs.
In some cases, it is also useful in higher-level frameworks.
For exemple, the [MiddlewareFilter] attribute in MVC Core uses New() internally to execute a piece of ASP.NET Core middleware inside the MVC framework (i.e. as a filter). MVC Core creates a small pipeline around the middleware, builds it into a RequestDelegate, then runs the HttpContext through it. Just like ASP.NET Core does with your 'main' pipeline built in Startup.cs.
Thanks to this feature, we can reuse a piece of general-purpose ASP.NET Core middleware, from inside MVC.
For more information, see MiddlewareFilterBuilder.cs in ASP.NET MVC Core.
It appears to be there to branch [clone] the original instance (as can be demonstrated in src/Microsoft.AspNet.Http/Extensions/MapExtensions.cs). There was also a previous MapWhenExtensions.cs, but it appears to have been removed from the dev branch.)
I suspect it's an artifact of a previous design that would provide the ability to bind middleware based on circumstances without affecting the root's configuration. The fact that it's been there since before IBuilder was refactored to IApplicationBuilder and that most dependencies were in files that have since been removed from the dev branch, I would venture a guess that it's old news.
Of course it's hard to tell given neither the interface nor the base implementation are commented.

Resources