I recently migrated my web application from ASP.net to.NETCore, I have already registered the DBcontext using DI in my startup.cs
services.AddDbContext<MyContextDB>
(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")),
....
public partial class MyContextDB: IdentityDbContext<USER>, IMyContextDB
...
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLazyLoadingProxies();
}
I have also avoided the use of "using" to retrieve data through the context , and I verified that I don't have any call to manually "Dispose()" the context
However I keep getting this exception whenever I reach this part of the application :
public class Licence : ILicence
{
private static IOptionsMonitor<LicenceConfiguration> _appSettings;
private readonly MyContextDB _context;
public Licence(MyContextDB context, IOptionsMonitor<LicenceConfiguration> optionsAccessor)
{
_context = context;
_appSettings = optionsAccessor;
}
public LICENCECODE GetLicenceCode(string key)
{
LICENCECODE LicenceCode = null;
LicenceCode = _context.LICENCECODE.SingleOrDefault(l => l.LICENCEKEY == key);
return LicenceCode;
}
}
"Cannot access a disposed object. A common cause of this error is
disposing a context that was resolved from dependency injection and
then later trying to use the same context instance elsewhere in your
application. This may occur if you are calling Dispose() on the
context, or wrapping the context in a using statement. If you are
using dependency injection, you should let the dependency injection
container take care of disposing context instances.\r\nObject name:
'MyContextDB'."
I've been through every article available on the internet about this exception but yet I can't identify the actual cause of it.
Could you please help me resolve it
The exception is raised specifically when this call is made :
public async Task<LICENCECODE> GetLicenceCode(string key)
{
LICENCECODE LicenceCode = null;
LicenceCode = await _context.LICENCECODE.SingleOrDefaultAsync(l => l.LICENCEKEY == key);
return LicenceCode;
}
PS: I tried to change the method to async because I thought that could be the cause of the issue but unfortunately it's still happening.
the call to that method is from another Model class
validLicence = _licence.CheckLicence(type.Name, ref message, out maxCount);
....
and then inside
CheckLicence
LICENCECODE LicenceCode = GetLicenceCode(LicenceKey).Result;
I guess it depends on how you are using your Licence class, but it might have to do with the lifetime of the request ending before you complete your work in Licence. This could for example happen if your controller action is asynchronous.
Try registering the class with transient lifetime instead:
services.AddTransient<ILicence, Licence>();
Related
I am developing a Blazor server app, where all clients will have a list of things, any one of these clients can update thing which should then trigger a callback telling all clients to call DbContext.Entry(thing).Reload() so they're up to date. This works all great and well until I refresh the page, then I get the Cannot access a disposed object error and I can't figure out how to get around it.
I have the follow services:
services.AddDbContextPool<MainDbContext>(...);
services.AddSingleton<RefreshService>();
RefreshService.cs:
public class RefreshService {
public Func<long, Task> OnRefreshThing { get; set; }
public void RefreshThing(long thingId) => OnRefreshThing?.Invoke(thingId);
}
Index.blazor:
protected override void OnInitialized() {
RefreshService.OnRefreshIssue += OnRefreshIssue;
}
private async Task OnRefreshThing(long thingId) {
// This works perfectly until I refresh the page & try to call it again
Thing thing = await MainDbContext.Things.FindAsync(thingId); // exception is thrown here
await MainDbContext.Entry(thing).ReloadAsync();
}
And here's an example of what triggers the error:
Thing thing = Things.Where(t => t.ThingId == 1);
thing.Name = "New name";
RefreshService.RefreshThing(thing.ThingId);
You can modify the RefreshService to be Scoped not Singleton
The AddDbContextPool does not dispose the instance of the dbcontext completely, it resets the instance to its default state and it could be because of the reset that it can't access it again
I'm trying to call a method from IActionResult using Task.Run. This is the Exception I am getting.
An exception of type 'System.InvalidOperationException' occurred in
Microsoft.EntityFrameworkCore.dll but was not handled in user code:
'An exception was thrown while attempting to evaluate a LINQ query
parameter expression. To show additional information call
EnableSensitiveDataLogging() when overriding DbContext.OnConfiguring.'
Inner exceptions found, see $exception in variables window for more
details. Innermost exception System.NullReferenceException : Object
reference not set to an instance of an object.
Initialization of EntityContext instance:
private readonly EntityContext _context;
public ApiController (
UserManager<User> userManager,
SignInManager<User> signInManager,
ILoggerFactory loggerFactory,
IMemoryCache memoryCache,
EntityContext context,
IRepository repository,
Context session,
IEmailService emailService,
IHostingEnvironment environment,
IHttpContextAccessor contextAccessor, ViewRender view, IStringLocalizer<SharedResources> localizer) : base (userManager, signInManager, loggerFactory, memoryCache, context, repository, session, contextAccessor) {
//_view = view;
_emailService = emailService;
this.environment = environment;
_localizer = localizer;
this._context = context;
}
Startup.cs
services.AddEntityFrameworkNpgsql ()
.AddDbContext<EntityContext> (
options => options.UseNpgsql (connectionString)
);
Calling method from controller:
if(updated){
Task t1 = Task.Run(()=>SendEmailAsync(entity,true,responsible,_context));
}else{
Task t1 = Task.Run(()=>SendEmailAsync(entity,false,responsible,_context));
}
Method I am calling:
public void SendEmailAsync (Activity entity, bool updated, User responsible, EntityContext ctx) {
List<string> emailList = new List<string> ();
var mail = new MailComposer (_emailService, environment, _localizer);
if (responsible.IsSubscriber) {
emailList.Add (responsible.Email);
}
if (entity.Participants.Count > 0) {
foreach (var item in entity.Participants) {
var p = ctx.Users.Where(c=>c.Id==item.Participant.Id).FirstOrDefault(); //This is where I am getting an exception.
if (p.IsSubscriber) {
emailList.Add (p.Email);
}
}
}
if (emailList.Count != 0) {
var emailArray = emailList.ToArray ();
if (updated) {
mail.SendActivityUpdate (entity, emailArray);
} else {
mail.SendActivityCreated (entity, emailArray);
}
}
}
For your issue, this is caused by that you are reference a scoped service EntityContext from another thread. For EntityContext, it will be disposed when the request returned from Controller.
As the suggestion from Chris, you may call t1.Wait(); to complete the t1 task before the request return back to client. By calling t1.Wait();, the EntityContext _context will not be disposed and then you won't get any error.
For another option, you may try pass IServiceProvider to create a new EntityContext instead of referencing the existing EntityContext which is created by Controller
public class HomeController : Controller
{
private readonly ApplicationDbContext _context;
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<HomeController> _logger;
public HomeController(ApplicationDbContext context
, IServiceProvider serviceProvider
, ILogger<HomeController> logger)
{
_context = context;
_serviceProvider = serviceProvider;
_logger = logger;
}
public IActionResult TestTask()
{
Task t1 = Task.Run(() => SendEmailAsync(_serviceProvider));
//t1.Wait();
return Ok();
}
private void SendEmailAsync(IServiceProvider serviceProvider)
{
var context = _serviceProvider.CreateScope().ServiceProvider.GetRequiredService<ApplicationDbContext>();
var result = context.Student.ToList();
_logger.LogInformation(JsonConvert.SerializeObject(result));
}
}
Task.Run will start a new thread, and unless you await it, the existing thread where the action is running will keep going, eventually returning and taking the context with it, which your method running in the new thread depends on. If you do await it, then there's no point in running in a separate thread; you're just consuming additional resources for no good reason.
In short, you should not be using Task.Run for this at all. It's not the same as "running the background". Instead, you should schedule the email to be sent on different process or at the very least an IHostedService. You can use QueuedBackgroundService. There's an implementation available at https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.2&tabs=visual-studio#queued-background-tasks.
I have some SignalR hubs which may need to access some transient and singleton dependencies. Hooking the creation of the Hub is easy and works just fine however SignalR does its own Dispose() call on the created Hub rather than notifying the dependency resolver and letting it get involved in the disposal.
This isn't such a big deal if the dependencies are registered singletons, but if they're registered as transients then they'll never get disposed (if that was required) and Windsor will keep them alive until the Windsor container is collected (when the web server is shutting down anyway).
I see several possible ways of handling this...
a) Someone here points out a way to subclass SignalR's HubDispatcher class so that it can do proper disposal. It's not part of SignalR's standard DependencyResolver so this might be difficult / impossible
b) Some other class in SignalR, elsewhere in the pipeline, can be overridden or easily replaced so that we could subclass HubDispatcher and ensure that subclass is used. From what I can tell this would have to be the Owin middleware class HubDispatcherMiddleware. Is there some way to force Owin to not register this class and instead register my own version of this (which in turn uses my own HubDispatcher)?
c) There's some way of intercepting the Dispose() call made by SignalR on my Hub classes so that a call could be made back to Windsor to ensure any dependencies are properly disposed and released from the container
d) Studiously avoid using transient lifestyle dependencies and instead pass in typed factories so that we can resolve and release each dependency via the typed factory within the Hub
At the moment (d) is the only one I know how to do. (a) or (b) would be great. (c) is mostly covered by this post http://kozmic.net/2010/01/27/transparently-releasing-components-in-windsor/, however, the interceptor requires that Dispose() be called via IDisposable. SignalR's HubDispather class' implementation of hub disposal is
private static void DisposeHubs(IEnumerable<IHub> hubs)
{
foreach (var hub in hubs)
{
hub.Dispose();
}
}
No casting to IDisposable there... Also Dispose() on the Hub class is virtual and that blog post implies that a virtual Dispose() could add some complexity (I'm not quite sure how much and I don't know enough about Castle's interceptors and whether or not that missing cast to IDisposable can be worked around anyway).
I appreciate I've written this question for a fairly narrow audience - those who have used Windsor AND SignalR and care about more than just resolving dependencies. Every example I've found, including those on StackOverflow, seems to just ignore the release of dependencies.
Thanks!
I've had a bit similar problem but with Unity instead of Castle Windsor.
My requirements:
I wanted to avoid singleton registrations on the container.
All objects are resolved in Hub and should be disposed on Hub destruction.
Registrations reused across Web Api and SignalR.
Object lifetime is managed by HierarchicalLifetimeManager - child containers resolve and manage separate object instances. Registered like this:
container.RegisterType<IMessageService, MessageService>(new HierarchicalLifetimeManager());
This is my solution:
[HubName("exampleHub")]
public class ExampleHub : Hub
{
IUnityContainer _container;
public CarrierApiHub(IUnityContainer container) // container itself injected in hub
{
_container = container.CreateChildContainer(); // child container derived from the main container.
}
public async Task<int> UnreadMessagesCount()
{
// Here i'm resolving instance of IMessageService which depends on
// other registrations specified on the container. Full object graph
// is constructed and destroyed on hub disposal.
var messageSvc = _container.Resolve<IMessageService>();
return await messageSvc.CountUnreadOf(UserId);
}
protected override void Dispose(bool disposing)
{
_container.Dispose(); // child container destroyed. all resolved objects disposed.
base.Dispose(disposing);
}
private int UserId
{
get
{
// only an example
var claim = ((ClaimsPrincipal)Context.User).GetClaim("user_id");
return int.Parse(claim.Value);
}
}
}
SignalR and dependency resolver configuration:
public static class ConfigureSignalR
{
public static void Initialize(UnityContainer unityContainer, IAppBuilder app)
{
app.Map("/signalr", map =>
{
var resolver = new AppSignalRDependencyResolver(unityContainer);
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJavaScriptProxies = false,
EnableJSONP = true, // Required for IE 9 (supports only polling)
Resolver = resolver
};
map.RunSignalR(hubConfiguration);
});
}
}
Dependency resolver implementation:
public class AppSignalRDependencyResolver : DefaultDependencyResolver
{
protected IUnityContainer _container;
public AppSignalRDependencyResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this._container = container.CreateChildContainer();
}
public override object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return base.GetService(serviceType);
}
}
public override IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _container.ResolveAll(serviceType).Concat(base.GetServices(serviceType));
}
catch (ResolutionFailedException)
{
return base.GetServices(serviceType);
}
}
protected override void Dispose(bool disposing)
{
_container.Dispose();
base.Dispose(disposing);
}
}
My problem is that in the main class I have some osgi references that work just fine when the class is call. But after that all the references became null. When I close the main windows and call shutdown method, the hubService reference returns null. What do I do wrong here?
private void shutdown() {
if(hubService == null) {
throw new NullPointerException();
}
hubService.shutdownHub(); // why is hubService null?
}
// bind hub service
public synchronized void setHubService(IHubService service) {
hubService = service;
try {
hubService.startHub(PORT, authenticationHandler);
} catch (Exception e) {
JOptionPane.showMessageDialog(mainFrame, e.toString(), "Server", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
}
// remove hub service
public synchronized void unsetHubService(IHubService service) {
hubService.shutdownHub();
hubService = null;
}
If a field can be read and written by multiple threads, you must protect access to read as well as write. Your first method, shutdown, does not protect the read of hubService so that the value of hubService can change between the first read and the second read. You don't show the declaration of the hubService field. You could make it volatile or only read when synchronized (on the same object used to synchronized when writing the field). Then your shutdown implementation could look like:
private volatile IHubService hubService;
private void shutdown() {
IHubService service = hubService; // make a copy of the field in a local variable
if (service != null) // use local var from now on since the field could have changed
service.shutdownHub();
}
I assume your shutdown method is the DS deactivate method? If so, why do you shutdown in the unset method as well in the shutdown method?
Overall the design does not seem very sound. The IHubService is used as a factory and should return some object that is then closed in the deactivate method. You made the IHubService effectively a singleton. Since it must come from another bundle, it should handle its life cycle itself.
Since you also do not use annotations, it is not clear if your set/unset methods are static/dynamic and/or single/multiple. The following code should not have your problems (exammple code with bnd annotations):
#Component public class MyImpl {
IHubService hub;
#Activate
void activate() {
hubService.startHub(PORT, authenticationHandler);
}
#DeActivate
void deactivate() {
hubService.shutdown();
}
#Reference
void setHub(IHubService hub) { this.hub = hub; }
}
I have seen many examples using Entity Framework in MVC3 applications, they are very simple demos which only have one mvc3 web project with edmx inside it.
So, they can use the best practice for open and close connection by "using" statement:
using(var context = new SchoolEntities())
{
// do some query and return View with result.
}
And, It can use lazy load (navigation properties) inside the "using" statment correctly, because the context is not yet
disposed:
foreach(var item in student.Course)
{
// do something with the navigation property Course
}
All things seems to be perfect until it becomes an n-tier application.
I created DAL, BLL, and a MVC3 UI.
The DAL have edmx inside it, and operator classes like SchoolDA.cs:
public class StudentDA()
{
public Student FindStudent(int studentId)
{
using(var context = new SchoolContext())
{
// do query, return a student object.
}
}
}
Then, in the BLL, if I use:
var student = studentDa.FindStudent(103);
then invoke it's navigation property:
student.Course
I will get an error (of course):
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
So, I have to change StudentDA.cs like this:
public class StudentDA() : IDisposable
{
private SchoolEntites context;
public StudentDA()
{
context = new SchoolEntities();
}
public void Dispose()
{
context.Dispose();
}
public Student FindStudent(int studentId)
{
// do query, return a student object.
}
}
Then, the BLL will change like this:
public Student FindStudent(int id)
{
using(var studentDa = new StudentDA())
{
// this can access navigation properties without error, and close the connection correctly.
return studentDa.FindStudent(id);
}
}
All things seem to be perfect again until it meet Update() method.
Now, if I want to update a student object which is taken from BLL.FindStudent(), the context.SaveChanges() will return 0, because the context is already disposed in the BLL.FindStudent(), and nothing will be updated to database.
var optStudent = new StudentBO();
var student = optStudent.FindStudent(103);
student.Name = "NewValue";
optStudent.Update(student);
Does anyone have idea on how to use EntityFramework in 3 tire application? or how can I manage the context correctly. I will use navigation propertites very often in the web layer, but I can't always remain connection open to consume the server memory.
There are multiple ways to handle EF context's lifetime. In web apps, usually context is unique for an HttpRequest. For example, if you want to handle this manually in a web application and have a per Thread/HttpRequest EF context, you can do so with the following (Code copied from http://www.west-wind.com/weblog/posts/2008/Feb/05/Linq-to-SQL-DataContext-Lifetime-Management):
internal static class DbContextManager
{
public static DbContext Current
{
get
{
var key = "MyDb_" + HttpContext.Current.GetHashCode().ToString("x")
+ Thread.CurrentContext.ContextID.ToString();
var context = HttpContext.Current.Items[key] as MyDbContext;
if (context == null)
{
context = new MyDbContext();
HttpContext.Current.Items[key] = context;
}
return context;
}
}
}
And then you can easily use:
var ctx = DbContextManager.Current
But I suggest you leave the lifetime management to an IoC framework like Autofac, Castle Windsor, or Ninject which automatically handle the creation/disposal of your registered obejcts along with many other features.
Thanks for your answer Kamyar. I came across this whilst looking for a simple strategy to manage the ObjectContext lifetime without having to use an IoC framework, which seems a bit overkill for my needs.
I also came across your other post here, for disposing of the context at the end of the request.
Thought this might be useful for others coming across this, so just posting my implementation of your code here:
Context manager class -
internal static class MyDBContextManager
{
//Unique context key per request and thread
private static string Key
{
get
{
return string.Format("MyDb_{0}{1}", arg0: HttpContext.Current.GetHashCode().ToString("x"),
arg1: Thread.CurrentContext.ContextID);
}
}
//Get and set request context
private static MyDBContext Context
{
get { return HttpContext.Current.Items[Key] as MyDBContext; }
set { HttpContext.Current.Items[Key] = value; }
}
//Context per request
public static MyDBContext Current
{
get
{
//if null, create new context
if (Context == null)
{
Context = new MyDBContext();
HttpContext.Current.Items[Key] = Context;
}
return Context;
}
}
//Dispose any created context at the end of a request - called from Global.asax
public static void Dispose()
{
if (Context != null)
{
Context.Dispose();
}
}
}
Global.asax (MVC) -
public override void Init()
{
base.Init();
EndRequest +=MvcApplication_EndRequest;
}
private void MvcApplication_EndRequest(object sender, EventArgs e)
{
MyDBContextManager.Dispose();
}