Autofac - share instance in scope and child scopes - asp.net-core

I have an ASP.NET Core 2.2 application and I'd like to configure a service to be "singleton" for a request. Using InstancePerLifetimeScope works as long as you don't create child scopes. There are some processes which are running in child scopes, created from the scope of the request.
Using InstancePerRequest doesn't work in ASP.NET Core 2.2 (this is basically what I need).
Did anyone encounter this situation and found a solution?
using(var scope1 = container.BeginLifetimeScope())
{
var w1 = scope1.Resolve<Worker>(); // should resolve worker 1
using(scope2 = scope1.BeginLifetimeScope())
{
var w2 = scope2.Resolve<Worker>(); // should resolve same worker as w1
}
}
using(scope3 = container.BeginLifetimeScope())
{
var w3 = scope3.Resolve<Worker>(); // should resolve another worker
}

Looks like you may want to define Worker as InstancePerMatchingLifetimeScope and then tag your outer scope with the same ID as you registered Worker with.
See the docs on tagged scopes: https://autofaccn.readthedocs.io/en/latest/lifetime/working-with-scopes.html#tagging-a-lifetime-scope

Related

How to inject the .NET Core [IServiceProvider] itself into services?

How to inject the [IServiceProvider] interface into custom services? I mean after the [Startup] class finishes construction of [IServiceProvider] from [IServiceCollection] set of bindings. How do I then subscribe to the newly created [IServiceProvider] built after method [ConfigureServices] invoked?
If you want to call your service inside startup you should create a scope
// initial database
using (var scope = app.ApplicationServices.CreateScope())
{
var initDatabase = new YourClass(scope.ServiceProvider.GetService<YourServiceInterface>());
}
But Accessing to IServiceProvider in other services don't make sense. If you describe more You could get the right answer.

Using UserManager not working inside Timer

In my project I am trying to get a user based on it's email adress every second with the UserManager but when I do this I get the following error Cannot access a disposed object Object name: 'UserManager1, but this is when I do it inside of a Timer(). If I just do it once there is no problem, how can I fix this? This timer is inside a class that is being called by a SignalR Hub.
Code:
Timer = new System.Threading.Timer(async (e) =>
{
IEnumerable<Conversation> conversations = await _conversationsRepo.GetAllConversationsForUserEmailAsync(userMail);
List<TwilioConversation> twilioConversations = new List<TwilioConversation>();
foreach (Conversation conversation in conversations)
{
TwilioConversation twilioConversation = await _twilioService.GetConversation(conversation.TwilioConversationID);
twilioConversation.Messages = await _twilioService.GetMessagesForConversationAsync(conversation.TwilioConversationID);
twilioConversation.ParticipantNames = new List<string>();
List<TwilioParticipant> participants = await _twilioService.GetParticipantsForConversationAsync(conversation.TwilioConversationID);
foreach (TwilioParticipant participant in participants)
{
User user = await _userManager.FindByEmailAsync(participant.Email);
twilioConversation.ParticipantNames.Add(user.Name);
}
twilioConversations.Add(twilioConversation);
}
}, null, startTimeSpan, periodTimeSpan);
UserManager along with quite a few other types is a service that has a scoped lifetime. This means that they are only valid within the lifetime of a single request.
That also means that holding on to an instance for longer is not a safe thing to do. In this particular example, UserManager depends on the UserStore which has a dependency on a database connection – and those will definitely be closed when the request has been completed.
If you need to run something outside of the context of a request, for example in a background thread, or in your case in some timed execution, then you should create a service scope yourself and retrieve a fresh instance of the dependency you rely on.
To do that, inject a IServiceScopeFactory and then use that to create the scope within your timer code. This also applies to all other scoped dependencies, e.g. your repository which likely requires a database connection as well:
Timer = new System.Threading.Timer(async (e) =>
{
using (var scope = serviceScopeFactory.CreateScope())
{
var conversationsRepo = scope.ServiceProvider.GetService<ConversionsRepository>();
var userManager = scope.ServiceProvider.GetService<UserManager<User>>();
// do stuff
}
}, null, startTimeSpan, periodTimeSpan);

How to dynamically resolve controller with endpoint routing?

Upgrading to asp.net core 2.2 in my hobby project there is a new routing system I want to migrate to. Previously I implemented a custom IRouter to be able to set the controller for the request dynamically. The incoming request path can be anything. I match the request against a database table containing slugs and it looks up the a matching data container class type for the resolved slug. After that I resolve a controller type that can handle the request and set the RouteData values to the current HttpContext and passing it along to the default implementation for IRouter and everything works ok.
Custom implementaion of IRouter:
public async Task RouteAsync(RouteContext context)
{
var requestPath = context.HttpContext.Request.Path.Value;
var page = _pIndex.GetPage(requestPath);
if (page != null)
{
var controllerType = _controllerResolver.GetController(page.PageType);
if (controllerType != null)
{
var oldRouteData = context.RouteData;
var newRouteData = new RouteData(oldRouteData);
newRouteData.Values["pageType"] = page.PageType;
newRouteData.Values["controller"] = controllerType.Name.Replace("Controller", "");
newRouteData.Values["action"] = "Index";
context.RouteData = newRouteData;
await _defaultRouter.RouteAsync(context);
}
}
}
A controller to handle a specific page type.
public class SomePageController : PageController<PageData>
{
public ActionResult Index(PageData currentPage)
{
return View("Index", currentPage);
}
}
However I got stuck when I'm trying to figure out how I can solve it using the new system. I'm not sure where I'm suppose to extend it for this behavior. I don't want to turn off the endpoint routing feature because I see an opportunity to learn something. I would aso appreciate a code sample if possible.
In ASP.NET 3.0 there is an new dynamic controller routing system. You can implement DynamicRouteValueTransformer.
Documentation is on the way, look at the github issue

Can't get SignalR client events published with Aurelia Event Aggregator

I have a single page app based on Aurelia and I'm trying to get it to work with an existing SignalR backend. I've downloaded the SignalR javascript client and integrated it with the Aurelia app manually (i.e. I'm not using a proxy file). I'm able to connect to the SignalR hub and see the arrvive messages in the console.... so far so good. Now, I'm trying to use the Aurelia Event Aggregator so that when a new hub message arrives an event is fired and any components of the app subscribed to that particular event will do some work. The issue is that the SignalR event callback doesn't seem to be able to access the Event Aggregator object. Here's the code to illustrate the issue:
//Import statements omitted for brevity
#inject (EventAggregator)
export class MyService{
constructor(eventAggregator) {
this.ea = eventAggregator;
this.connection = $.hubConnection("http://localhost:8080/signalr", { useDefaultPath: false });
this.hub = this.connection.createHubProxy("myHub");
//Register a callback function to fire when a new hub message arrives
this.hub.on("sendMessage", this.processHubMessage);
//No issues so far - all this constructor code works fine
}
processHubMessage(message) {
// This doesn't work - this.ea is undefined in the scope of this function
this.ea.publish('deviceStatusUpdate', message);
}
}
The event aggregator object referenced within the callback function is not defined - I assume because it's not being called within the scope of the class. Is there a way to resolve this? How do I give the callback function access to the class properties (this.ea in my example).
Try using
this.hub.on("sendMessage", (message) => this.processHubMessage(message));
It's failing on you due to how this isn't what you're expecting it to be. By using a fat arrow function, this is what you expect it to be. This is a really frustrating part of JavaScript, but fat arrows provide a simple workaround for it.
I think you are missing the 'start' for your Proxy, also you may need to alias your view model to pass to the HubProxy.
This works for me:
constructor(eventAggregator){
this.eventAggregator = eventAggregator;
var signalrAddress = 'https://pathToYouServer';
var hubName = 'yourHubsName';
var connection = $.hubConnection(signalrAddress);
var eventHubProxy = connection.createHubProxy(hubName);
var vm = this;
eventHubProxy.on('yourBroadcastMessage', function(data) {
vm.eventAggregator.publish(data);
});
connection.start();
}

WCF app . Structure map Objectfactory losing instance of an Object

I am trying to get WCF work with Structuremap. I took most of the code from Jimmy Bogard's blog
Integrating StructureMap with WCF
I am reusing all my objects (Domain, NHIBERNATE , Service layer ) that was created for ASP.nET MVC application.I have a separate IoC Library where I bootstrap all regisrties
I have added global.asax and in Application Start Event this is what I have :
var webServiceRegistry = new WebServiceRegistry();
var bootStrapper = new IoC.BootStrapper();
bootStrapper.Start();
WebServiceRegistry is a normal class and in its constructor I have the following:
var appUser = new AppUser
{
Role = userDto.Role,
Email = userDto.Email,
Id = userDto.Id,
CompanyName = dealerDto.Name,
Name = userDto.Name,
IsImpersonated = false,
Impersonater = Guid.Empty
};
System.Threading.Thread.CurrentPrincipal = System.Web.HttpContext.Current.User = appUser;
ObjectFactory.Configure(x => x.For<IAppUser>().Use(appUser));
Everything goes fine - no errors
Things start to fail when my my wcf service class is being instantiated which has a Domainservice object (IDomainServiceObject domainServiceObject) in constructor with 202 error.
The failure is in DomainService Registry where it fails to get default instance of IAppUser
Edit
Initial problem was in that I had error in constructor of StructureMapServiceHost.
Now I dont get any error but I am not getting the instance of IAppUser that I inject. In place of that it creates a new instance of AppUser.
Do anyone have a clue as to why this happens?
I have tried adding HttpContextScope , HybridHttpOrThreadLocalScoped and still same result
I have conformed that at the time all registries are called in bootstrapper IAppUser instance is the once that was provided with values in it (and not created by StructureMap)
In Application Start it does create the whole graph .
As soon as it enters webmethod ILMSUser is a new instance.
Thank you
Since you want the same object back every time you can use singleton
this.For<IAppUser>().Singleton().Use(appUser);