I have a web app that uses the iBATIS.NET library.
The DAO is configured by using an XmlDocument, so the code is very similar to what they show in the documentation:
XmlDocument anXmlDoc = someSupportClass.GetDynamicXmlDocument();
DomDaoManagerBuilder builder = new DomDaoManagerBuilder();
builder.Configure(anXmlDoc);
The documentation says right below that:
The DaoManager instance that is built from a dao.config file is aware
of all of the contexts contained within the configuration file. The
context basically bundles DAO implementations together with a session
handler. The DaoManager knows which DAOs and session handler belong to
which context. When you request a DAO instance from the DaoManager,
the proper session handler will be provided with it. Therefore, there
is no need to access the context or session handler directly. Your DAO
knows how it works.
This does not appear to be true. In a threaded process, the following exception is thrown randomly:
WebSessionStore: Could not obtain reference to HttpContext at
IBatisNet.DataAccess.SessionStore.WebSessionStore.ObtainSessionContext()
at
IBatisNet.DataAccess.SessionStore.WebSessionStore.get_LocalSession()
at IBatisNet.DataAccess.DaoManager.IsDaoSessionStarted() at
IBatisNet.DataAccess.Configuration.DaoProxy.Intercept(IInvocation
invocation, Object[] arguments)
The application may run fine for days or even months at a time, but every once in awhile this exception is thrown. The only solution I can find mentioned anywhere is to swap out the SessionStore for a HybridWebThreadSessionStore (mentioned here).
As the documentation says above, this shouldn't be necessary. If I wanted to force it though, how would I go about overriding the SessionStore created by the DomDaoManagerBuilder?
The issue seems to be caused by a race condition in the iBatis.NET framework when the application starts up. If a call to the database is made on the main thread before a call to the database is made on a separate thread, then the separate threads will raise the error since they don't have an HttpContext stored in the SessionStore.
Basically it went Startup -> db call on main thread -> db call on separate thread
When it should have been Startup -> db call on separate thread -> db call on main thread
Basically I just changed the order in which events fire to make sure the db call on the thread is called at least once before anything on the main thread happens.
This post describes the same problem
THE SETUP
In my Global.asax, I kick-start a background process using the Timer
class. This Timer class uses a delgate DoTimerBasedStuff() which is
called periodically. The DoTimerBasedStuff() method accesses two
different databases, MySQL and SQL Server. Both are setup properly
using their MySQLMapper and SQLServerMapper classes.
Aside from a couple of these background threads, the application also
has a web front which accesses both databases using typical .aspx
pages and classes inherited from Page. Nothing fancy.
THE PROBLEM
If the application is started by going to index.aspx using a browser
(this page doesn't do any db stuff but triggers Global.asax) and no
other actions are taken until the first call of DoTimerBasedStuff()
all is well and both the background process and the web users are
fine. IBatis does everything right.
BUT if I start the application by going to index.aspx and then
immediately do some work via the web which accesses a database (before
DoTimerBasedStuff() is executed), the DoTimerBasedStuff() method has
trouble accessing the HttpContext and gives the following error:
Exception: WebSessionStore: Could not obtain reference to HttpContext
at IBatisNet.DataMapper.SessionStore.WebSessionStore.ObtainSessionContext()
at IBatisNet.DataMapper.SessionStore.WebSessionStore.get_LocalSession()
at IBatisNet.DataMapper.SqlMapper.QueryForObject(String
...
The error occurred because you run ibatis in different threads.
You can make use of a new instance of HybridWebThreadSessionStore just before making a query to the database.
var map = new Hashtable
{
{ "FilterA", "MyFilter" }
};
SqlMap.SessionStore = new HybridWebThreadSessionStore(SqlMap.Id);
var listadoJobs = SqlMap.QueryForList<EventoJob>(SbsIbatisConstantes.ListarJobs, map).ToList();
You can check this reference Here
That worked for me.
Related
I'm using Thread to store Locale and pass it down the layers.
In my middleware I set the selected locale in the current thread as follow:
Thread.SetData(Thread.GetNamedDataSlot('SelectedLocale'), selectedLocale /* I get this value form the request */);
Then in the rest of my code, I use this line to access that data:
var selectedLocale = Thread.GetData(Thread.GetNamedDataSlot('SelectedLocale'));
However, this sometimes works, and sometimes returns null.
I used var threadId = Thread.CurrentThread.ManagedThreadId and realized that Id changes sometimes.
Why is it so? How can I make sure that I'm using the same thread during my request processing?
Update
I'm using the same technique for my APIs and for my Razor Page applications.
My APIs work just fine. They never fail.
However, my Razor Page applications fail almost 70% of the time. But they also work sometimes.
I think there must be something related to the Razor Pages here.
I'm using Thread to store Locale and pass it down the layers.
I'm not using async/await in my code
If you're still thinking in threads and not using async/await, you're doing it wrong. Threads are too low-level of a construct to be using in application code, especially web application code.
It's all tasks and contexts now. If you use Razor pages, stuff will be handled async by the framework. Just use the HttpContext to pass entities from one middleware to the next.
Though the HttpContext has its own problems.
More reading: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-6.0, https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-6.0.
I try to develop an extension for Microsoft Edge based on native messaging and the official guide provides the example. And there is synchronization of access to the dictionaries of AppServiceConnections and their Deferrals in the OnBackgroundActivated method, but there is no such a thing in other event handling methods...
So my question is about UWP App Service threading model. Is it guaranteed that only one event handling method can be performed at a time? Or should I provide a correct synchronization of access to my data?
Is AppServiceConnection thread safe? Can I use SendMessageAsync from different threads at the same time? Or should I synchronize its usage?
I guess your issue is that you didn't see lock keyword inside events like OnAppServiceRequestReceived, OnAppServicesCanceled and so on, which is to do thread synchronization, and you're not sure if you should do this by yourself.
I think the answer should be no.lock inside OnBackgroundActivated is ensured to set correct desktopBridgeConnectionIndex or connectionIndex. Without the keyword lock inside these event handles not means that the event handle must be triggered only one time at a time. For one app service, if client A is connecting the app service, at the same time, another client B asks for the same app service, for this scenario the app service will spin up another instance of the same background task. So that for client A, its app service connection there is no side effect on client App B. In another words, each app service connection has its own instance, messages sending based on one app service connection have no influence with others. You may reference this video to look more details about app service, app service relative is about starting from 25th minute.
If you check the code snippet inside the event, you may see there are code lines to judge the request is from which app service connection, for example this.desktopBridgeConnection = desktopBridgeConnections[this.currentConnectionIndex].You will send message to correct AppServiceConnection, and this should be thread safe. If you met actual thread save issue when performing this, you could ask issue with testing details.
I have an ASP.NET application which uses a component in an class library assembly to make web service calls. The component uses the Thread Pool or some sort of home brewed threading solution to spawn background threads in which synchronous web service calls are made.
A logging component is used in the ASP.NET application and by helper classes that the component calls from the background threads spawned when it does service calls.
In ASP.NET a HttpModule creates logging context object and stores it in the HttpContext.Current.Items collection. The helper classes used in the ASP.NET application and in the helper classes fetch the logging context object from HttpContext.Current.Items when a message needs to be logged in order to decorate the logged message with information that puts the logged message into a context.
When the helper classes are called directly from ASP.NET, HttpContext.Current is available.
When the helper classes are called from background threads created by the component, HttpContext.Current is null and so there is no logging context available to them when messages are logged; the logged messages are useless.
I don't have control over the component which creates the threads for making service calls. If I did, I would arrange for the logging context obect to be copied and passed into the child thread.
My logging context object cannot be static, because it would be overwritten by concurrent ASP.NET request threads and that would be bad.
The members of my logging context object (simple int/string properties) could be marked ThreadStatic, which would work, and I would not need to use HttpContext.Current.Items anymore.
What I really need is a to make the .NET runtime copy the object (or even pass a reference; either would do) and makes it available to child threads automatically.
I was wondering whether I could add a <system.threading> element to web.config and nominate a helper class for creating threads like you can do for Web Requests in %lt;system.net>
I also wondered whether I could mark my Logging Context object with some attribute that causes it to be copied automatically.
I looked into log4nets LogicalThreadContext, tried it, but it didn't work. I think that's for passing logging context information across processes or appdomain boundaries.
What mechanism does log4net's LogicalThreadContext used behind the scenes? Something from System.Runtime.Remoting? Is that deprecated now?
My environment is .NET 4, so maybe with the parallel extensions or enhancements to threading in .NET 4 this is now possible.
Anyone any idea if this is at all possible? I'm beginning to think not.
Update *
I have had to do the following:
Task<IEnumerable<Account>> accountsTask = Task<IEnumerable<Account>>.Factory.StartNew
(
instrumentationContext =>
{
var parentContext = instrumentationContext as Site.Instrumentation.InstrumentationContext;
if (Site.Instrumentation.InstrumentationContext.Current == null && parentContext != null)
Site.Instrumentation.InstrumentationContext.Current = parentContext;
return GetAccounts();
},
Site.Instrumentation.InstrumentationContext.Current
);
Where the GetAccounts() method calls on another class which in turn depends on Site.Instrumentation.InstrumentationContext.Current
The problem is, I would rather NOT have to change the code to explicitly pass in and set this state object in the child thread - I want the .NET Framework to do that for me automatically, so that the code (above) that creates the task is none the wiser and does not have to be changed.
If no-one else contributes with alternatives, Jon gets the green tick as I figured that was my only realistic choice albeit with tasks not threads.
If I understand you correctly all you need to do is to pass an object to a thread signature so what's wrong with a parameterized thread start ??
static void Main(string[] args)
{
object j = new object();
Thread t = new Thread(()=>childThread(j));
t.Start();
}
private static void childThread(object someObject)
{
// do work
}
While writing some aysnc controllers in ASP.NET MVC2, I ran up against a situation where I had to call AsyncManager.Sync. It got me wondering:
When I retrieve HttpContext.Current, what's going on? How does ASP.NET know which HttpContext I'm after? How is the current context associated with this thread, and how is it retrieved?
Thread scoped storage is used, this is called Thread Local Storage.
This mechanism allows data to be affinitized with a thread i.e. only the thread that allocates the data sees the data. This is useful for creating so called ambient programming models such as HttpContext.Current and TransactionScope. The mechanism allows data to be accessible at any time on the executing thread without having to "tramp" data through method parameters for instance. It's an elegant solution for certain context\orthogonal problems.
There are number of ways of using TLS including the ThreadStaticAttribute and Thread.SetData\GetData.
I have a web app that currently uses the current HttpContext to store a LINQ Data Context. The context is persisted for the current request, on a per user basis, per Rick Strahl's blog:
string ocKey = "ocm_" + HttpContext.Current.GetHashCode().ToString("x")
Thread.CurrentContext.ContextID.ToString();
if (!HttpContext.Current.Items.Contains(ocKey))
{
// Get new Data Context and store it in the HTTP Context
}
However, I have some scripts that execute from the global.asax file, that don't have an HttpContext. The HttpContext.Current is NULL, because the server is the one making the "request".
Is there an equivalent object that I can use to store the Data Context? So I don't have to worry about re-creating it, and attaching/detaching objects? I only want to persist the context for the lifetime of my processes.
UPDATED:
I am currently trying to use a static variable in my DAL helper class. on the first call to one of the methods in the class the DataContext is instantiated, and stored in the static variable. At the end of my process, I call another method that calls Dispose on the DataContext, and sets the static variable to NULL.
Can you not just use a static variable specifically for those scripts? That will have the same life-time as the AppDomain. You should probably think carefully about any concurrency concerns, but it sounds like the simplest way to keep a value around.
(I've just checked, and although one instance of HttpApplication can be used to service multiple requests, each one only serves one request at a time - which suggests that multiple instances are created for concurrent request processing. I haven't validated this, but it does sound like it wouldn't be safe to keep it in an instance variable.)
EDIT: Josh's answer suggests that you want this to be per-thread. That sounds slightly odd to me, as unless you've got a lot of these events occurring, you're quite likely to only ever see them execute on different threads, making the whole sharing business pointless. If you really do want that sort of thing, I'd suggest just using an instance variable in the HttpApplication-derived class - for exactly the reason described in the paragraph above :)
Why not use the current HttpContext? The scripts in your global.asax file are all the result of a request coming into the server, so there should be a context associated with that request which you can grab.
I don't understand the need for generating the key based on the hashcode or the thread. There is going to be a separate instance of HttpContext for each request that comes in, and that instance is going to be specific to the thread that is processing the request. Because of that, the key is pretty much worthless when it's based on the instance of HttpContext and the thread.
Also, how do you dispose of the DataContext when you are done? It implements IDisposable for a reason, so I would recommend against a shared instance like this.
UPDATE
In the comments, it indicates that there is a timer that is running that is executing the scripts. Instead of the timer, I would recommend setting up a Scheduled Task which will call a webservice or predetermined page on the site which will perform the task. Then you will always have an HttpContext to work with.
HttpContext.Current is a static method and should be available from anywhere as long as the code is executing within the context of a request.
In your case your not executing within the context of a request, You could look at using Application.Cache but I would caution against holding a DataContext open. I am not very famillar with linq to entities, so I could be wrong, but generally caching data base related items such as connections is bad.
I would also recommend that you consider moving the logic out of your global.asax and to a windows service. This would let you have more control over these tasks, for example you can shut them down seperatley of the web site.
Edit
As JS points out you could use a static variable. You could also define an instance variable marked with ThreadLocal attribute. This will give each thread its own copy of the variable, and can eliminate contention. Since you want each thread to have its own copy anyways.
Is there a reason why these need to be handled the same way as the other DataContexts? It seems to me that if the context is only needed inside the event handling routine, you shouldn't need to keep it around. Especially if it is in Application_Start (as per your comment), I wouldn't bother caching it anywhere -- just use it locally and pass it to the other methods as needed.
Set the DataContext as the state parameter when creating the timer. Based on the info you posted on the comments, it seems to me that your DataContext is more related to the timers than anything else.
Also avoid using the same DataContext for different timers, because you would end up with mixed modifications from the different timers. Also make sure your same timer logic isn't run twice, since it would cause the same i.e. too short period with no control.