Dependency injected DbContext in a SignalR hub does not pull latest data - kendo-ui

In my ASP.NET Core MVC site, I have a SignalR hub that has my DbContext injected into the constructor. The hub pulls data from the database and send it to a kendo ui grid for the user to view. This data is filtered in that hub on which group is selected (stored in the database).
The group selection is done outside the context of the hub. When I change the users selected group the page reloads to update various UI elements. When the signalr hub is then called, the selected group is still set as what it was prior to the change. After digging for a bit I came across this issue on the signalr github. What I understand is because the hub is transient, the DbContext is as well and since the hub is long running the DbContext is never updated.
Is there a simple way around this while still dependency injecting the DbContext or do I need to create and dispose a new context for every call? If so what is the best way to go about doing that and still pass the connection string from the appsettings.json?
EDIT
I am currently using Microsoft.AspNetCore.SignalR.Server and not the new Microsoft.AspNetCore.SignalR library.

The only way I could get around this issue with Microsoft.AspNetCore.SignalR.Server was to add a DbContextOptionsBuilder<T> singleton to the the ConfigureServices method in Startup.cs and then call that in a using(...) in the hub. While I feel this is a dirty way around the issue, I also believe it is the only way around the issue. Microsoft recently deprecated SignalR-Server and are moving to a new code base at SignalR. Hopefully this issue will be addressed in their new version.
Startup.cs
DbContextOptionsBuilder<PortalDbContext> builder = new DbContextOptionsBuilder<PortalDbContext>();
builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
services.AddSingleton(builder.Options);
Hub Classes
using (PortalDbContext dbContext = new PortalDbContext(_dbContextOptions))
{
...
}

Related

Is there a simple way to auto register [Exports] in a Prism app? WPF .NET 4.8

I used to be on a project that used Prism and when we needed a new service to do something, we'd just create an interface, a concrete class that implemented that interface and exported it, and then it just became available everywhere for [ImportingConstructor]. We didn't need to manually register it or anything. I no longer have access to that project, but I don't think there was any reflection magic that was done manually to accomplish this.
I'm in a new company and we are starting up a project using MEF / Prism and I'm trying to accomplish the same thing, but as of right now, I'm having to manually register items in order to import them. What am I missing?
I'm in .NET 4.8 WPF app
Additional info
we are basing our project from this website
https://prismlibrary.com/index.html
This is our app class
public partial class App
{
protected override Window CreateShell()
{
return Container.Resolve<ShellWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IStartupActionService, StartupActionService>();
containerRegistry.RegisterSingleton<IGeneralNavigationService, GeneralNavigationService>();
containerRegistry.RegisterSingleton<IExperimentSetupNavigationService, ExperimentSetupNavigationService>();
containerRegistry.RegisterSingleton<IProtocolSetupNavigationService, ProtocolSetupNavigationService>();
containerRegistry.RegisterSingleton<IOurProjectNavigationService, OurProjectNavigationService>();
containerRegistry.RegisterSingleton<IOurProjectUiService, OurProjectUiService>();
containerRegistry.RegisterManySingleton<WcfClientService>();
containerRegistry.RegisterSingleton<IControlClientService, ControlClientService>();
}
}
Why do I have to register each new service?
I've been reading about MEF, DryIoc, and others and I'm just not getting clear answers. Is there not a way to just have everything with an [Export] become immediately available for import?
Something else I need to do, that I think this whole registering thing is messing me up on is trying to come up with a way to have "dialogs" but tie them to a neutral class to make it more MVVM happy.
Dialog -> a region that pops open when you call a method. This method currently takes in a UserControl, assumed to have already been constructed and its ViewModel datacontext already attached.
What I would like to do and don't know how to start is
use a neutral container class to open one of these dialogs (similar to interaction request Notification
using attributes, attach an attribute to a view that indicates "I support this neutral container class" (assumed only one view per container)
this view supports [ImportingConstuctor] to bring in its ViewModel
the viewmodel itself supports [ImportingConstuctor] to bring in services needed
again, the desire to NOT need to register these items manually as we add them. Would like to add a service interface, the concrete class that [Export]s the interface and have it just available to the viewmodel and other services, and same for the views and viewmodels, export attribute tag them as necessary and have them just available to either/both grab an instance of them or manually create an instance of them and have their [ImportingConstructors] handled for me.

NHibernate + ASP.NET Identity + Autofac cache issue

I'm building a profile page with update form. After submitting the form with new data and several page refreshes I see sometime new and sometimes old data. It depends on thread handling current request. One thread contains new data and another one old. NHibernate is configured using ThreadStaticSessionContext and NoCacheProvider. In Autofac UserStore, OwinContext.Authentication and UserManager are configured as InstancePerRequest.
I tried to change ThreadStaticSessionContext to CallSessionContext and it started working normally. So the question is: why it works(ThreadStaticSessionContext is preferable for multithread apps) and what negative effects can it bring?
Thanks!
ThreadStaticSessionContext is for long running processes such as windows services or windows apps. For web applications you want to be implementing Session Per Request. This is what the WebSessionContext is for.
I actually don't use any of the contexts and just wire it up myself. See my answer here for an example.

StructureMap3 HybridHttpOrThreadLocalScoped with no HttpSessionState

I am trying to figure out how to setup a StructureMap3 configuration, that works in both a WebApi and in a Console application, like:
For<ISession>().HybridHttpOrThreadLocalScoped().Use(p => p.GetInstance<TestingContainer>().GetSession());
For console apps I would like the object to live as long as the thread lives, and for websites as long as the http-session lives.
This is possible with MVC websites because HybridHttpOrThreadLocalScoped use the HttpSessionState to determine whether to create a new instance or to reuse an existing instance.
WebApi doesn't have this HttpSessionState and therefore HybridHttpOrThreadLocalScoped won't work.
If I didn't care about the console app, then I would probably configure structuremap with Transient() or AlwaysUnique or similar.
So, what is the equivalent to HybridHttpOrThreadLocalScoped when there are no HttpSessionState instance.
Thank you.
EDIT
-to rearrange the question...
In general you should favor Nested Containers for lifecycle management. The reasons behind this are exactly what you've just noted, that in some situations using either Thread, HTTP, or hybrid scoped simply doesn't work. I've seen it cause huge issues before where people assume DB connections are being disposed because they are in other environments, but in one environment they aren't. Also, the explicitness is nice.
To do this set the dependencies you want disposed per request to Transient (the default) and dispose of the nested container at the end of the request. I've written about this workflow in webapi here. Additionally the official docs recommend this nuget.
For the console app you'll want to do something like this:
//parent Container set up at app start
public void On_UserAction()
{
//global container set up at app start, either use ObjectFactory (bad, deprecated and to be removed) or just keep track of it yourself.
using(var nestedContainer = GlobalContainer.GetNestedContainer())
{
var dependency = nestedContainer.GetInstance<DependencyThatHandlesUserInput>();
}
}
and that's it, the using block handles all the disposal for you.
If you have any other questions please ask, I've spent a lot of time on this sort of thing :).

ASP.NET MVC 3, RavenDB, & Autofac Issue Plus 2 Other Autofac Questions

NOTE: There are 3 questions in here and I did not make separate questions since they are all somewhat related to the same code.
I have the following code that registers the connection to my RavenDB in the Application_Start once per the application's life cycle:
var store = new DocumentStore { Url = "http://localhost:8080" };
store.Initialize();
builder.RegisterInstance(store).SingleInstance();
Now this works fine and this is something that should be created only once per the application's life cycle. Now I wanted to add in the DocumentSession to Autofac so I tried to add in this in the Application_Start:
var session = store.OpenSession();
builder.RegisterInstance(session).SingleInstance();
In my UserRepository I have the following constructor:
public UserRepository(DocumentStore store, DocumentSession session)
When I try to run this, I get the follow runtime error:
Cannot resolve parameter 'Raven.Client.Document.DocumentSession Session' of constructor 'Void .ctor(Raven.Client.Document.DocumentStore, Raven.Client.Document.DocumentSession)'
That error to me sounds like Autofac does not think it has a DocumentSession however that is what store.OpenSession() returns so it should. Anyone know what would be causing this error? Am I not setting the session variable correctly (it is the same as the store variable which works fine)?
Another thing which may or may not be related to the above issue is how do I add an instance of an object to Autofac per request instead of per the applications life cycle? While the RavenDB DocumentStore object should only be created once be the life application cycle, the DocumentSession should be created once per the request (maybe creating it per application level is causing the error above).
One last question I will throw there about Autofac (mildly related to the code above) is about releasing the objects. If you take a look at this tutorial:
http://codeofrob.com/archive/2010/09/29/ravendb-image-gallery-project-iii-the-application-lifecycle.aspx
The last piece of code:
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
and the point of this code is to prevent leaking the sessions. Now is this something I also need to worry about for Autofac and if so, how would I do this in Autofac?
I'm guessing you want something like:
builder.Register(c => c.Resolve<DocumentStore>().OpenSession()).InstancePerLifetimeScope();
"The default ASP.NET and WCF integrations are set up so that InstancePerLifetimeScope() will attach a component to the current web request or service method call." - Autofac: InstanceScope
Basically, in a web app, InstancePerLifetimeScope handles the one per HTTP context aspect, and also disposes any types that implement IDisposable.
There was also the issue that OpenSession returns a IDocumentSession instead of a DocumentSession. Changing my class to look for a IDocumentSession along with doing what Jim suggested worked, thanks.

wp7 odata v2 dataservicestate save and restore methods tombstoning example needed

I am looking for an example of how to use the new DataServiceState Save and Restore methods in a WP7 application in order to tombstone a datacontext - I cannot find any examples and the approach I used resulted in an exception
this saves the data context correctly
PhoneApplicationService.Current.State["DataContext"] = DataServiceState.Save(this.Model.Entities);
this attempts to restore it after the app is re-activated
var dc = (PhoneApplicationService.Current.State["DataContext"] as DataServiceState).Restore();
but throws an exception
An item could not be added to the collection. When items in a DataServiceCollection are tracked by the DataServiceContext, new items cannot be added before items have been loaded into the collection.
This is the same exception I get if I try to reload a datacontext that I stored "directly" (without using the DataServiceState.Save method) in the PhoneApplicationService.Current.State. I cannot find any offical documentation on the new ODATA v2 DataServiceState class or examples.
thanks
Michael
I am looking for an example of how to use the new DataServiceState Save and Restore methods in a WP7 application in order to tombstone a datacontext
Are you sure? First link - bottom of the page.
Have you tried the walkthrough here?
How to: Preserve and Restore Application State for Windows Phone
Storing and retrieving datacontext is tricky due to serialization and object reference issues. The MSFT team is working on improving DataServiceState. I've succeeded in saving and restoring the context in a WP7 app, by storing the DataServiceState returned by Save() in the app state (just like you've done). Then on activated, I first instantiate my DataServiceClient (which contains the context and the DataServiceCollection), and then I call a RestoreData method in the client and pass the retrieved DataServiceState to it. The method restores the context and DSC within the DataServiceClient.

Resources