Autofac with self hosted WCF service and object disposal - wcf

I'm injecting a business layer into a self-hosted (InstanceContextMode=per-call) WCF service by leveraging AutoFac's ServiceHost.AddDependencyInjectionBehavior() extension (as described in the Autofac documentation)
My business layer uses components that cannot be re-created each time a new request comes in (let's say it needs a persistent database connection).
As such, when building the container I'd like to register the BL service as a Single instance, i.e.:
builder.RegisterType<BusinessLayer>()
.SingleInstance();
The business-layer injection into the WCF service is working fine; my issue is that:
Dispose() is not called on ANY services created in the container: not just the Business layer itself, but the 'persistent' services too.
I'd expect this to happen for the BL service itself. From the Autofac docs again:
If you have singleton components (registered as SingleInstance()) they will live for the life of the container. Since container lifetimes are usually the application lifetime, it means the component
won’t be disposed until the end of the application.
, but why are none of my 'child' (Autofac-registered) services (i.e the 'IPersistentService' below) disposed when the lifetime scope is -- given that I'm not explicitly making them 'SingleInstance'?
Note:: this is still the case if I manually dispose the business layer service within the lifetime scope after I close the ServiceHost
E.g. (IDisposable implementations omitted for brevity):
[ServiceContract]
public interface IMyService
{
void DoStuff();
}
public class MyService : IMyService
{
IBusinessLayer _bl;
public MyService(IBusinessLayer bl)
{
_bl = bl;
}
public void DoStuff()
{
_bl.BLDoStuff();
}
}
public interface IBusinessLayer
{
void BLDoStuff();
}
public class BusinessLayer : IBusinessLayer
{
IPersistentService _service;
public BusinessLayer(IPersistentService service)
{
_service = service;
}
public void BLDoStuff()
{
// Do something that requires a 'cached' / persistent component
_service.DoSomethingWithPersistentConnection();
}
}
public interface IPersistentService : IDisposable
{
void DoSomethingWithPersistentConnection();
}
With Autofac registrations looking something like:
builder.RegisterType<BusinessLayer>()
.SingleInstance();
builder.RegisterType<MyPersistentService>()
.As<IPersistentService>()
.OnActivated(e => e.Instance.Start());

As Steven mentioned, what you experience here is a Captive Dependency problem. In other words, a singleton (BusinessLayer, registered with .SingleInstance()) keeps a lifetime-scoped or transient dependency (MyPersistentService, registered by default as transient).
Put it this way, dependencies of singleton services will always be singletons themselves, no matter how they were registered in the container. The diagram in Mark Seeman's article that Steven linked to gives a good view of this.
I think you can achieve what you expect, but your registrations are wrong.
My business layer uses components that cannot be re-created each time a new request comes in (let's say it needs a persistent database connection).
As such, when building the container I'd like to register the BL service as a Single instance
This is where the problem is. It's the dependency of the business service that has to be registered as a singleton, not the business service itself. This means you could have Autofac create a different instance of BusinessLayer for each WCF call, but the MyPersistentService instance injected into would always be the same. Does this make sense? Your registrations would then look like:
builder
.RegisterType<BusinessLayer>()
.As<IBusinessLayer>()
.InstancePerLifetimeScope(); // a new instance per WCF call
builder
.RegisterType<MyPersistentService>()
.As<IPersistentService>()
.OnActivated(e => e.Instance.Start())
.SingleInstance(); // one same instance for the lifetime of the application
The one instance of MyPersistenService would then be disposed of only after disposing the root container (that you created by calling builder.Build()) after you close the Service Host.

Related

How does one consume Bugsnag from singleton?

I have an ASP.NET core application that implements a singleton service.
I would like errors to be sent to Bugsnag so I've added IClient bugsnag to my constructor but am getting the following error during startup:
Cannot consume scoped service 'Bugsnag.IClient' from singleton
I cannot find anything in the Bugsnag docs that mentions IClient being scoped or how to construct a singleton instance to use in my application.
As mentioned in the comments, a possible solution would be to use IServiceScopeFactory to create a scope to use in the singleton. This is not ideal because the whole reason for using Bugsnag is to have something that catches all unhandled errors in the application and reports them to a central point for monitoring.
UPDATE: since posting the question I came across a GitHub issue addressing this problem.
In short, you couldn't register the service as singleton , since the IClient has been registered as scoped but it called in the singleton service.
When we have a scoped instance, each time we load the page, a new instance of our ChildService is created and inserted in the parent service.
Whereas when we do a singleton, it keeps the exact same instance (Including the same child services). When we make the parent service a singleton, that means that the child service is unable to be created per page load.
ASP.NET Core is essentially stopping us from falling in this trap of thinking that a child service would be created per page request, when in reality if the parent is a singleton it’s unable to be done. This is why the exception is thrown.
If you want to use iclient in the singleton service, it's impossible. The right way is make that singleton service to scoped.
Update:
As #JHBonarius says, we could inject the IServiceScopeFactory to the singleton sercive and manage the scope service.
More details, you could refer to below codes:
public class Singleton : ISingleton
{
private readonly IServiceScopeFactory scopeFactory;
public Singleton(IServiceScopeFactory scopeFactory)
{
this.scopeFactory = scopeFactory;
}
public void MyMethod()
{
using(var scope = scopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<yourservice>();
// when we exit the using block,
// the IServiceScope will dispose itself
// and dispose all of the services that it resolved.
}
}
}

Shared service provider NServiceBus and ASPNET Core

I'm creating a way to publish integration events via NServiceBus that are published from within an operation executed in a handler. The path I've chosen is bridge the IIntegrationEventProvider with IEventCollectionPublisher to get the published events from domain layer.
public sealed class Bridge : IIntegrationEventProvider /* Infrastructure */,
IEventCollectionPublisher /* Domain */
{
private readonly List<object> _events = new List<object>();
void IEventCollectionPublisher.Publish(object domainEvent) { _events.Add(domainEvent): }
IReadOnlyCollection IIntegrationEventProvider.GetEvents() => _events;
}
Since NServiceBus has its own service provider (IBuilder) I need to resolve the class doing the application operation from the IServiceProvider that is made available to pipeline in ServiceScopedBehavior. Doing this I can get the bridge instance that contains the events published from domain layer and publish them as integration events using NServiceBus.
I published a Gist with (hopefully) the code pieces needed to grasp what I'm trying to achieve.
The question is: can I instruct NServiceBus to just delegate calls to the application service provider instead of building it and copy all instructions in endpoint.UserContainer<ServiceBuilder>()? Below is an example
internal sealed class Handler : IHandleMessages<Command>
{
public async Task Handle(Command message, IMessageHandlerContext context)
{
// Resolved from ASPNET DI
var useCase = context.GetService<CommandUseCase>();
// _useCase is resolved NSB DI since injected from constructor
Debug.Assert(ReferenceEquals(useCase, _useCase), "");
await useCase.Execute().ConfigureAwait(false);
}
}
This way I could inject to correct scoped application class in the handler constructor instead of resolving it from the scope provided by IServiceProvider that is made available from context.Extensions.Get<IServiceScope>().ServiceProvider.
Thanks for help
Regards
I think ASP.NET Core integration sample could be useful. Starting from version 7.2 sharing of the DI infrastructure between ASP.NET and NServiceBus is much simpler. There is also a specialized NServiceBus.Extensions.Hosting adapter package that adds UseNServiceBus API.

Injecting a service singleton into actor (Akka.NET) in ASP.NET Core

I am trying to inject a singleton of a service into an actor (Akka.NET) with ASP.NET Core's built-in DI container.
I have done the following in ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
// ..
// Register singleton of service
services.AddSingleton<IMyService, MyService>();
// Build service provider
var provider = services.BuildServiceProvider();
// Create actor system
var system = ActorSystem.Create("MyActorSystem");
// Inject service singleton into actor
directory.MyActorRef
= system.ActorOf(MyActor.Props(provider.GetService<IMyService>()), "myactor");
}
The issue is that the instance of MyService in the actor is different from the instance that is injected into the rest of the application - i.e. it is not a singleton.
What am I doing wrong and is there a better way of doing this?
That's because you create a separate IoC container inside your ConfigureServices
// Build service provider
var provider = services.BuildServiceProvider();
This line will create a new service provider (IoC container). When you resolve services from it, they are effectively singletons (since its not resolved from a scoped provider).
You shouldn't ever call .BuildServiceProvider() inside your ConfigureServices method, except when using 3rd party container and create it (i.e. when using Autofac).
Anyways, if you for some reason have to create the provider inside of ConfigureServices you need to change signature of ConfigureServices to
// Return value from void to IServiceProvider
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var provider = services.BuildServiceProvider();
// don't call services.AddXxx(..) after this point! The container is already created and its registrations can't be changed
...
return provider;
}
This will make ASP.NET Core use this container instead of creating its own one and passing that to Configure Method.
While this may solve you immediate problem, its not very clean to do that kind of resolving inside ConfigureServices and you should use the docs (or ask a separate question) on how to correctly use DI with Akka.NET (Sorry not familiar with it, I'm Microsoft Orleans user :)).
A slightly better (still not fully correct since it works around the idea of DI) way would be to delay the instantiation of the actor until Configure method is called.
public void ConfigureServices(IServiceCollection services)
{
// ..
// Register singleton of service
services.AddSingleton<IMyService, MyService>();
}
public void Configure(IApplicationBuilder app)
{
// Create actor system
var system = ActorSystem.Create("MyActorSystem");
// Inject service singleton into actor
directory.MyActorRef
= system.ActorOf(MyActor.Props(app.ApplicationServices.GetService<IMyService>()), "myactor");
}
or
public void ConfigureServices(IServiceCollection services)
{
// ..
// Register singleton of service
services.AddSingleton<IMyService, MyService>();
}
// inject it in Configure
public void Configure(IApplicationBuilder app, IMyService myService)
{
// Create actor system
var system = ActorSystem.Create("MyActorSystem");
// Inject service singleton into actor
directory.MyActorRef
= system.ActorOf(MyActor.Props(myService), "myactor");
}
This will initialize and resolve your services in Configure.
Remarks regarding singletons, scopes and actors
P.S. keep in mind, you can't resolve scoped services from app.ApplicationServices or the service provider, it will throw an exception. This may become an issue when you want to use DbContext which, by default is registered as scoped service.
You can also register it as scoped with an override to AddDbContext, but be aware of "memory leaks", as the number of tracked objects grows, so will the memory consumption (and big number of tracked entities (>=10k) will decrease your tracker related operations significantly).
And with DbContext in mind, also keep in mind that EF and EF Core are not thread-safe, and can't be accessed by threads (or run multiple asynchronous operations, i.e. starting 5 queries w/o awaiting and then using await Task.WaitAll(...)).
While an actor is guaranteed to only be accessed by a single thread at a single time, the services aren't if you scope them.
How well this works depends on the Task Scheduler implementation used by Akka.NET (again, not familiar with it's internals - i.e. Orleans abstracts persistence behind storage providers).

Server Side WCF Service : How to reference/interact with other server components

I have a fairly simple design question about interaction between a self hosted WCF Service and other business classes.
Here is the WCF service contract :
/// <summary>
/// Represent requests on hardware components made by a client to the controler service
/// </summary>
[ServiceContract(CallbackContract = typeof(IHardwareServiceCallback))]
public interface IHardwareService
{
[OperationContract(IsOneWay = true)]
void OpenLeftDrawer();
[OperationContract(IsOneWay = true)]
void OpenRightDrawer();
}
The service implementation
public class HardwareService : IHardwareService
{
public void OpenLeftDrawer()
{
}
public void OpenRightDrawer()
{
}
}
A class which purpose is to handle the business logic regarding client calls on the server
class DrawerRequestManager
{
// Server side Business logic to handle OpenDrawer requests from client
}
Hosting scenario
Uri adrbase = new Uri(srvConfig.Address);
var host = new ServiceHost(typeof(HardwareService), adrbase);
host.AddServiceEndpoint(typeof(IHardwareService), srvConfig.Binding, srvConfig.Address);
host.Open();
Since this is the host that is managing the service instance lifetime, what is the proper way to handle the link between the service instance and business logic classes (DrawerRequestManager for exemple).
I'm using IOC container but i'm also interested in the response when not using IOC container.
Thanks in advance !
WCF uses parameterless constructor to create service objects, but there is a way to alter that. You need to implement your own instance provider.
You can inject your instance provider via ServiceHostFactory: see here.
Alternatively you can inject instance provider by using custom attribute for your service: see here.
Either way gives you full control of how services instances are created. You can use IOC there or just call constructor manually passing any parameters you want (e.g. reference to DrawerRequestManager instance).

Consuming wcf service with windows process?

I need initialize some structure in wcf service class as soon as possible after start of hosting service.
Now I host it in WinForms application and there I initialize this static structure.
ServiceHost host = new...
host.Open()...
new MyServiceClient().Initialize();
But I'm sure there is better way to do this. I know now it is inelegant solution...maybe little wcf-client running as windows process? (this client should be responsible only for calling this initializing method)
You can use the constructor of the service to do whatever initialization work is required.
// The service
public class MyService : IMyService {
// Constructor
public MyService() {
// Initialize things here
}
}
If the initialization work should only be performed once, you can make the constructor static. If the things being constructed are not static, you can make the service a singleton, depending on your performance needs. You can decorate the service with the following code to do that:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]