I'm considering putting the ObjectContext inside HttpContext.Current so that all logic in the same request can access to it without having to open/destroy each time.
In ObjectContextManager class i created this.
get {
string ocKey = "ocm_" + HttpContext.Current.GetHashCode().ToString("x");
if (!HttpContext.Current.Items.Contains(ocKey))
HttpContext.Current.Items.Add(ocKey, new JEntities());
return HttpContext.Current.Items[ocKey] as JEntities;
}
and then I call this static property every time i execute a query on current request.
public static JEntities CurrentObjectContext {
get {
if (ObjectContextManager == null)
InstantiateObjectContextManager();
return ObjectContextManager.ObjectContext;
//return new JobsEntities();
}
}
But it gets disposed when it tries to execute second query.
Can you tell me where i went wrong?
Disposed? Your code has nothing to do with disposing. If you get disposed context it means you most probably enclosed the context retrieval into using and you disposed the instance yourselves.
Related
I am moving an asp.net mvc5 application using EF6 to asp.net core MVC 3.0 using EF Core.
In my mvc5 application I have some administrative operation that modify the database and take a long time, so I use a pattern when I create a new DBContext that is not the one that is associated with the request context and then run the task in the background using Task.Run. This has been working fine for years.
In converting to .net core it was unclear how to create a new DBContext in the way that I was doing it in my old codebase. It seems like I should be able to create a Transient DBContext in these cases and all should be fine.
So I created a subclass of MyDbContext called MyTransientDbContex and in my Configure class I added this service:
services.AddDbContext<MyTransientDbContex>(options =>
options.UseSqlServer(
context.Configuration.GetConnectionString("MyContextConnection")),
ServiceLifetime.Transient, ServiceLifetime.Transient);
In my controller I inject the context in the action that needs the transient service and spawn a thread to do something with it:
public ActionResult Update([FromServices] MyTransientContext context) {
Task.Run(() =>
{
try {
// Do some long running operation with context
}
Catch (Exception e) {
// Report Exception
}
finally {
context.Dispose();
}
}
return RedirectToAction("Status");
}
I would not expect my transient context to be disposed until the finally block. But I am getting this exception when attempting to access the context on the background thread:
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.
Object name: 'MyTransientContext'.'
And indeed the _disposed flag is set to true on the context object.
I put a breakpoint on the constructer for MyTransientContext and "Made an Object ID" of the this pointer so that I could track the object. This transient object is being created and is the same one that is inject into my controller action. It's also the same object that I'm trying to reference when the exception is thrown.
I tried setting a data breakpoint on the _disposed member in order to get a callstack on when disposed is being set to true, but the breakpoint won't bind.
I also tried overriding the Dispose method on MyTransientContext, and it isn't called until my explicit dispose in the finally block, which is after the exception is thrown and caught.
I feel like I'm missing something fundamental here. Isn't this what the transient services are for? What would dispose a Transient service?
One last detail - MyTransientContext is derived from MyContext, which is in turn derived from IdentityDbContext (Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContex)
Edit: The reason that I went down the path of using a Transient was because of this ef core document page: https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext. It states that "...any code that explicitly executes multiple threads in parallel should ensure that DbContext instances aren't ever accessed concurrently. Using dependency injection, this can be achieved by either registering the context as scoped and creating scopes (using IServiceScopeFactory) for each thread, or by registering the DbContext as transient (using the overload of AddDbContext which takes a ServiceLifetime parameter)."
As xabikos pointed out, this seems to be overriden by the scoping of the asp.net DI system, where it looks like anything created by that system is scoped to the request context, including Transient objects. Can someone point out where that's documented so that I can better understand how to work with the limitations?
f you want manage the lifetime of service, you can instantiate it manually (or use a factory) :
public ActionResult Update()
{
Task.Run(() =>
{
using(var context = new MyTransientContext(...))
{
try
{
// Do some long running operation with context
}
catch (Exception e)
{
// Report Exception
}
}
}
return RedirectToAction("Status");
}
Or you can use IServiceProvider to get and manage a service :
public class MyController
{
private IServiceProvider _services;
public MyController(IServiceProvider services)
{
_services = services;
}
public ActionResult Update()
{
var context = (MyTransientContext)_services.GetService(typeof(MyTransientContext));
Task.Run(() =>
{
using (context)
{
try
{
// Do some long running operation with context
}
catch (Exception e)
{
// Report Exception
}
}
}
return RedirectToAction("Status");
}
}
You mixed the concepts of transient objects that are created by internal DI container asp.net core provides.
You configure the MyTransientContext to be transient in the internal DI system. This practically means that every time a scope is created then a new instance is returned. For asp.net application this scope matches an HTTP request. When the requests ends then all the objects are disposed if applicable.
Now in your code, that is a synchronous action method you spawn a Task with Task.Run. This is an async operation and you don't await for this. Practically during execution this will be started but not wait to finish, the redirect will happen and the request will end. At this point if you try to use the injected instance you will get the exception.
If you would like to solve this you need change to an async action and await on the Task.Run. And most likely you don't need to spawn a new Task. But you need to understand that this is not probably the best way as it will need for the long operation to finish before the redirect takes place.
An alternative to this would be to use a messaging mechanism, and send a message that triggers this operation. And you have another component, like worker service that listens for those messages and process them.
I have a following code example that is used in ASP.NET MVC application.
The purpose of this code is to create "fire and forget" request for queuing some long running operation.
public JsonResult SomeAction() {
HttpContext ctx = HttpContext.Current;
Task.Run(() => {
HttpContext.Current = ctx;
//Other long running code here.
});
return Json("{ 'status': 'Work Queued' }");
}
I know this is not a good way for handling HttpContext.Current in asynchronous code, but currently our implementation not allows us to do something else.
I would like to understand how much this code is dangerous...
The question: Is it theoretically possible that setting the HttpContext inside Task.Run, will set the context to totally another request?
I think yes, but I'm not sure. How I understand it:
Request1 is handled with Thread1 from thread pool, then while Thread1 is handling absolutelly another request (Request2), the code inside Task.Run will set context from Request1 to Request2.
Maybe I am wrong, but my knowledge of ASP.NET internals not allows me to understand it correctly.
Thanks!
Let me bump a little internals on you:
public static HttpContext Current
{
get { return ContextBase.Current as HttpContext; }
set { ContextBase.Current = value; }
}
internal class ContextBase
{
internal static object Current
{
get { return CallContext.HostContext; }
set { CallContext.HostContext = value; }
}
}
public static object HostContext
{
get
{
var executionContextReader = Thread.CurrentThread.GetExecutionContextReader();
object hostContext = executionContextReader.IllogicalCallContext.HostContext;
if (hostContext == null)
{
hostContext = executionContextReader.LogicalCallContext.HostContext;
}
return hostContext;
}
set
{
var mutableExecutionContext = Thread.CurrentThread.GetMutableExecutionContext();
if (value is ILogicalThreadAffinative)
{
mutableExecutionContext.IllogicalCallContext.HostContext = null;
mutableExecutionContext.LogicalCallContext.HostContext = value;
return;
}
mutableExecutionContext.IllogicalCallContext.HostContext = value;
mutableExecutionContext.LogicalCallContext.HostContext = null;
}
}
So
var context = HttpContext.Current;
is equal to (pseudocode)
var context = CurrentThread.HttpContext;
and inside your Task.Run something like this happens
CurrentThread.HttpContext= context;
Task.Run will start new task with thread from thread pool. So you're telling that your new thread "HttpContext property" is reference to starter thread "HttpContext property" - so far so good (well with all the NullReference/Dispose exceptions you'll be facing after your starter thread finishes). Problem is if inside your
//Other long running code here.
You have statement like
var foo = await Bar();
Once you hit await, your current thread is returned to thread pool, and after IO finishes you grab new thread from thread pool - wonder what its "HttpContext property" is, right ? I don't know :) Most probably you'll end with NullReferenceException.
The issue you will run into here is that the HttpContext will dispose when the request is complete. Since you aren't awaiting the result of the Task.Run, you are essentially creating a race condition between the disposal of the HttpContext and it's usage within the task.
I'm pretty sure that the only issue your task will run into is a NullReferenceException or an ObjectDisposedException. I don't see any way where you could accidentally steal another request's context.
Also, unless you are handling & logging exceptions within your task, your fire and forget will throw and you'll never know about it.
Check out HangFire or consider using a message queue for processing backend jobs from a separate process.
Can I able to access appSettings section in my ASP.NET web.config file from a method in another referenced Class Library project when it is called as a new Thread?
I'm accessing the setting through a property as
private static string TempXmlFolder
{
get
{
return System.Web.HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["ReceiptTempPath"] ?? "~/Receipts/TempXML");
}
}
There is an extension method for the matter to generate the receipt.
internal static void GenerateReceipt(this IMatter matter)
{
try
{
string XmlFile = TempXmlFolder + "/Rec_" + matter.MatterID + ".xml";
// ...
// Generating receipt from the matter contents
// ...
// Saving generated receipt
}
catch (Exception ex)
{
ex.WriteLog();
}
}
I'm calling the receipt generation as a new thread from the class library like
Thread printThread = new Thread(new ThreadStart(this.GenerateReceipt));
// To avoid exception 'The calling thread must be STA, because many UI components require this' (Using WPF controls in receipt generation function)
printThread.SetApartmentState(ApartmentState.STA);
printThread.Start();
// ...
// Do another stuffs
// ...
// Wait to generate receipt to complete
printThread.Join();
But since the HttpContext.Current is null inside the Thread, I'm not able to access the current web server configuration file.
Can you suggest there any way other than passing the current HttpContext to the Thread? If no, what are the things I've to take care to keep thread safety?
Edit #1
Currently I'm passing the HttpContext to the thread like
System.Web.HttpContext currentContext = System.Web.HttpContext.Current;
Thread printThread = new Thread(() => this.GenerateReceipt(currentContext));
and in the function,
internal static void GenerateReceipt(this IMatter matter, System.Web.HttpContext htCont)
{
string TempXmlFolder = htCont.Server.MapPath(ConfigurationManager.AppSettings["ReceiptTempPath"] ?? "~/Receipts/TempXML");
//...
Pass the TempXmlFolder into the thread. Don't rely on HttpContext.Current. Alternatively, pass the value of HttpContext.Current to the thread and calculate the value of TempXmlFolder later.
You can pass the value using any way you want. Maybe a field or a local variable that you capture with a lambda.
I use a ThreadLocal variable in an ASP.NET HttpHandler. I assumed it will result in a new variable per request.
I have some strange behavior in my application. When a ThreadLocal variable is created and disposed in an ASP.NET page?
What happens if the same thread is used by ASP.NET later for another request? Does it result in a new ThreadLocal variable or the previously created value (which was used with another request) will be used?
If ThreadLocal variables are disposed when the thread is actually disposed, then my assumption fails with ASP.NET (since threads get back to pool and are not unique per request)
ASP.NET can and will reuse threads between requests- in fact, if memory serves it uses a thread from the normal .NET thread pool for each request. You are probably better off using session state instead.
Try with this:
public class WebRequestLocal<T>
{
private readonly Func<T> _getter;
private readonly object _id = new object();
public WebRequestLocal(Func<T> getter)
{
_getter = getter;
}
public T Value
{
get
{
HttpContext httpContext = HttpContext.Current;
if(httpContext == null)
throw new Exception("HttpContext unavailable.");
if (httpContext.Items.Contains(_id))
return (T)httpContext.Items[_id];
return (T)(httpContext.Items[_id] = _getter());
}
}
}
Web service calls are asynchronous in flex, but I wanted to wrap a web service call in a class to provide synchronous encapsulation. Something like the below - the user could call getMyMethodResult and get the result returned by the web service. I expected the thread that recieved the soap response would populate the variable _result and mean that getMyMethod would, after a time, find _result is not longer null. But it doesn't! Can anyone explain why this does not work?
public class myClass
{
private var _result:Object;
public function myClass()
{
//create a web service object
...
// Add listener
_service.addMyMethodListener(myMethodListener);
}
public function getMyMethodResult()
{
_service.myMethod();
while (_result == null)
{
// count a variable or something (unimportant)
}
return _result;
}
private function myMethodListener(event:Event):void
{
_result = event.result;
}
}
There's is absolutely no support for that. The event loop runs between frames and as long as you block the execution with your (infinite) loop, your myMethodListener function will not be called. Anyway, this would be a terrible idea since the absence of threading in the Flash Player will cause your UI to freeze while you wait for your service to return. You should just drop that idea.