I've registered an Entity Framework DBContext using standard code like this:
public void ConfigureServices(IServiceCollection services)
{
[...]
services.AddDbContext<MyDbContextType>(ServiceLifetime.Scoped);
}
And this works just great for services called from controllers that require EF services.
However I have a couple of controllers that are special. They start jobs on new threads that run past the lifetime of the web request. When these jobs use my DbContext (or use services that use my DbContext) an error is thrown because the scoped instance has already been disposed.
Is there a way to override the service lifetime of my injected DbContext just for certain controllers? Or is there another solution you could suggest?
You should not override this behavior. Instead, the code you run on a background thread should run in its own scope. This means that the first thing that the background thread does is create a new IServiceScope using the IServiceScopeFactory. From this scope you resolve the service you wish to use and you call that service. At the end of the operation you dispose your scope.
For instance:
private IServiceScopeFactory factory;
new Thread(() =>
{
using (var scope = this.factory.CreateScope())
{
// Resolve
var service = scope.ServiceProvider.GetRequiredService<IService>();
// Use
service.DoStuff();
// Dispose scope
}
}).Start();
For more information on working with DI in multi-threaded applications, take a look at this documentation. Although the documentation is written for a specific DI Container, it is generic in nature and the advice applies to your DI Container as well.
Related
I have a simple C# .NET Core 5 Console Application that I need to add dependency injection (Microsoft.Extensions.DependencyInjection) to. I know how to do this if it suppose to start a micro service but what If I want to just run it as a regular Console Application with DI?
I got this code :
static void Main(string[] args)
{
var serviceName =
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
var configurationBuilder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json").Build();
var appSettings = configurationBuilder.Get<AppSettings>();
Log.Information("{#serviceName} test starting up.", serviceName);
Host.CreateDefaultBuilder(args)
.UseMyAppMQ(context => context.UseSettings(appSettings.MQSettings))
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration))
.ConfigureServices((hostContext, services) =>
{
services
.Configure<MQSettings>(configurationBuilder.GetSection("MQSettings"))
.AddTransient<ITestController>(s => new TestController());
})
.Build().Run();
Log.Information("{#serviceName} test closing down.", serviceName);
}
I need a entry point where I can run my underlaying class run method, but how?
Regards
You need to implement IHostedService interface (or extend BackgroundService base class) and register it with services.AddHostedService<YourServiceClass>() or
builder.Services.AddHostedService<YourServiceClass>(), if using .NET 6 minimal API as described in official docs. In this case IHostedService.StartAsync will be your entry point.
However, it does seem very inefficient, if all you need is just a simple console app with DI. As #Panagiotis Kanavos suggests you can build the host without running it, because then you can use it as a wrapper around DI container and resolve any registered service. In this case the entry point for your code is the next line after you've built your host, where you can resolve any registered dependency with
var host = Host.CreateDefaultBuilder(args)
...
.Build();
host.Services.GetService<YouService>()
But it is still an inefficient solution for just a console app, because you only need DI container, but not the entire host. Just use any third-party DI framework (like Autofac, Ninject or any other) instead of Microsoft.Extensions.DependencyInjection. Their setup is usually quite minimalistic and you will get just DI container with you services without anything else. You can still use configuration package and loggers, just register them in your container similarly to how you've done it before with UseXxxx methods.
I have a .Net Core 2.0 console application. The main() method is like this:
public static async Task Main()
{
// create host builder
var hostBuilder = new HostBuilder();
var myApp = new MyApplication();
// Build host
var host = hostBuilder
.ConfigureHostConfiguration(myApp.ConfigureHostConfiguration)
.ConfigureServices(myApp.ConfigureServices)
.ConfigureLogging(myApp.ConfigureLogging)
.Build();
// Initialise
await myApp.InitialiseAppAsync(host);
// Run host
await host.RunAsync(CancellationToken.None);
}
The MyApplication class sets up the application configuration in ConfigureHostConfiguration(), it then configures up the dependencies in ConfigureServices() some of which register a Message Handlers to handle specific Messages types from an Azure Service Bus. The application needs to do some initialisation from within InitialiseAppAsync(). When host.RunAsync() is called, the a console application is run indefinitely and the Message Handler receives execution as soon as a message is available on the Azure Service Bus. This is all great and working fine.
What I'd like to do is create a new project under the same solution which contains some end to end tests (using XUnit). I'd like to be able to override some of the dependencies (with test mocks, using NSubstitute), leaving the other dependencies as they are configured in the service.
I'm guessing I'd need to create my own HostBuilder in my test, so I'll need to be able to setup the mocks before the host.RunAsync() call is made within the test.
Does anyone know how I can do this? Or what is the best practice for doing this?
Ultimately, what I'm trying to do is be able to override some (but not all) of my real dependencies in my Console Application with mocks, so I can do some end to end tests.
Thanks in advance
There are multiple ways to achieve this. You can set up the environment variable "environment" when you start up your application. Then you would need to run your application passing it like this:
dotnet "MyApplication.dll" --environment end2endTests
Then you will be able to find the value you passed as the environment at IHostEnvironment instance which is injectable. This is how your DI registrations would look like:
services.AddScoped<IFoo>(provider =>
{
var env = provider.GetRequiredService<IHostEnvironment>();
if (env.EnvironmentName == "end2endTests")
{
return new TestFoo();
}
return new RealFoo();
});
I've just upgraded a solution from .NET 3.5 to .NET 4
In the same time, I've upgraded all external libraries to the latest version, so Castle is now upgraded from 2.5.2 to v3.0
I've some code that register db access that throw now an Exception when I try to resolve:
[Castle.MicroKernel.ComponentResolutionException] {"Could not obtain
scope for component DF.MailFlowAdapter. This is most likely either a
bug in custom IScopeAccessor or you're trying to access scoped
component outside of the scope (like a per-web-request component
outside of web request
etc)"} Castle.MicroKernel.ComponentResolutionException
The component is registered this way:
Container
.AddFacility<WcfFacility>()
.AddFacility<DataAccessAdapterFacility>()
.Register(Component
.For<SD.LLBLGen.Pro.ORMSupportClasses.IDataAccessAdapter>()
.ImplementedBy<MailFlowAdapter>()
.LifeStyle.PerWcfOperation())
The problem comes from the PerWcfOperation LifeStyle, but I don't know why: The project is a WCF project and the component is resolved when calling a WCF method.
This registration is working fine in the branch that use Castle 2.5.
The exception is thrown when Validating the wcf login/pwd (in a IAuthorizationPolicy that use a UserNamePasswordValidator), because I resolve an IDataAccessAdapter (to check login/pwd in the db).
Other piece of information:
The DataAccessAdapterFacility is an old code that register a component activator, I had to slightly change de code because model.Service changed to model.Services:
void Kernel_ComponentModelCreated(ComponentModel model)
{
foreach (var service in model.Services)
{
if (service == typeof(SD.LLBLGen.Pro.ORMSupportClasses.IDataAccessAdapter))
{
model.CustomComponentActivator = typeof(DataAccessAdapterActivator);
}
}
}
And the DataAccessAdapterActivator has in charge to create the object using a connection string in the config file:
protected override object InternalCreate(CreationContext context)
{
var connectionString = string.Empty;
if (ConfigurationManager.ConnectionStrings["Main"] != null)
connectionString = ConfigurationManager.ConnectionStrings["Main"].ConnectionString;
return new MailFlowAdapter(connectionString);
}
I think the code with DataAccessAdapterFacility/DataAccessAdapterActivator could be simplify using Factory but it's not the question here :)
So does someone have an idea on why I can't use PerWcfOperation lifestyle ?
I don't believe an OperationContext.Current is available at the point where a custom UserNamePasswordValidator is called. Is it possible to use another lifestyle for that component?
Ok Let's resume my discussion with Craig Neuwirt on the castle mailing list:
The behaviour has changed, in v2.5 is was falling back on a
transient lifestyle. But as it was not consistent (No info on when
the component was PerWcfOperation and when it was Transient) this has
been removed.
It's possible to do the same using a custom lifestyle scope accessor
I'll not post my code here as it's trivial once you've read how the Hybrid lifestyle are done in the castlecontrib project
I have 4 projects:
Core (IServer):
System
System.Core
DependencyResolver:
Core
StructureMap
Infrastructure (Service):
Core
External dependency
Console:
Core
DependencyResolver
Requierements:
I am trying to use StructureMap only in the DependencyResolver.
Furthermore the Console application should not know anything about Infrastucture.
When I do not want to reference StructureMap on my Console Application I have to build a ServiceLocator.
In the DependencyResolver I have a Bootstrapper that is responsible for calling StructureMap registry stuff (Register)
In my Console application I want to get an instance. For this I need to reference StructureMap. Another way would be to write a little wrapper around StructureMaps resolving methods.
Is there any other better way of decoupling the console from StructureMap?
While I see a reason for separating IoC register,resolve,release from the implementation of the application, I don't see any reason why the IoC container shouldn't be in the console application (the composition root) and the application implemention in another assembly instead.
That way the console application is very easy:
Create the container
Load the container configuration
Resolve the Application
Call run on the application and pass the console arguments along
dispose the container when the application exits the run method
With SM it look about like this:
public void Main(params string[] args)
{
using (var container = new Container())
{
container.LoadAllConfigurationModules();
container.AddRegistry<SomeRegistry>();
container.GetInstance<Application>().Run(args);
}
}
For things you can't create at startup you create a factory interface in your application assembly:
interface ISomeFactory { ISomeDependency CreateSomeDependency() }
and implement this interface in the console application by injecting the container and use it to resolve the instance. I guess the SM implementation looks like this:
public class SomeFactory : ISomeFactory
{
public SomeFactory(IContainer sontainer) { this.container = container; }
ISomeDependency CreateSomeDependency() { this.container.GetInstance<ISomeDependency>(); }
}
Other IoC container even have the functionallity to implement these interface factories automatically.
I'm building a WCF service that receives requests on an external IP and translates them into messages that are sent via NServiceBus.
One of my unit tests invokes Global.Application_Start(), which performs the configuration of the application, and then attempts to resolve the web service to
validate that the container can build up all of the dependencies.
This works fine when I'm using Configure.With() in my windows services, but
the call to Configure.WithWeb() fails in this context (presumably because the "bin"
directory does not exist?).
Is it possible to unit test a method that calls Configure.WithWeb(), or should I
just use the overload for Configure.With() that takes a directory name?
I created a new startup class like so:
public class NonWebRunAtStartup : IRunAtStartup
{
public void InitializeInfrastructure(object container)
{
Configure.With()
.StructureMapBuilder((IContainer) container)
.Log4Net()
.XmlSerializer()
.MsmqTransport()
.UnicastBus()
.LoadMessageHandlers()
.CreateBus()
.Start();
}
}
Then in my test, I ensured that my IOC container would use this one instead of the usual web-based one by adding this to my test:
IoC.Register<IRunAtStartup, NonWebRunAtStartup>();
This got me to a different error, which I'm still fighting with, which I'll ask as a separate question (now NSB can't load assemblies that are in NServiceBus.Core.dll, such as Antlr3.Runtime.dll).