I played with this some more over the weekend. I was able to use EXE servers without any special marshaling code (AspCompat="false"), so I assume ASP.NET handles that? Persisting the COM reference in the Session object appears to work ok. That has obvious scalability issues, but would probably be ok for my limited number of users. Persisting in the Cache object, with the idea of implementing a pool manager there shared by all sessions, also seems to work. Predicting the actual lifetime of these objects is proving to be a challenge. Still experimenting. I'm sure you know a lot more than I do about how this would actually behave on a live server.
Joel,
In order to persist EXE servers across requests you have to do thread marshaling which is rather difficult to do. VFP EXE servers are still STA components so that doesn't really change anything.
The only efficient way to do this (and this is what the Web Connection Managed MOdule does) is to spin up new threads and park the COM servers there so they always stay on that thread. This is relatively straight forward if you have a fire and forget type operation, but a bit more work if you need a result back.
Basically what I do in Web Connection is pass the state to the parked thread, then tell the thread to continue running. The thread then picks up the data and passes the data to the COM object, waits for completion and then sets known result data on return. The calling process just waits for this operation to complete and then picks up the return data to process and complete the request.
The advantage of this approach is that it effectively offloads the VFP processing to a purely single threaded operation - a dedicated thread for the vfp com object that stays alive. THere's no marshalling or other thread switching for VFP which is much more stable and since servers load once and stay loaded there's much less overhead for each service call.
Unfortunately it's not so nice to pass parameters back and forth as you have an indirect state mechanism, but I suppose one could write some wrappers that have Invoke("ServerMethod",param Args) that would effectively could do this for you more generically.
Overall screwing around with multi-threading for VFP servers is generally more pain than it's worth. It's so much easier to just let .NET do the multi-threaded processing and return the result from that processing in some sort of wrapper call.
+++ Rick ---
I suppose that make sense, I just didn't see it mentioned as a limitation anywhere compared to standard request handling. In any case, I'm just experimenting, and I would probably require out-of-process COM EXE's anyway. As far as I can tell, those don't require the AspCompat flag, but I could be wrong. I'd just have to be careful I don't fire up a new EXE for every request.
Thanks,
Joel
IIS marshals STA threads for a particular session to a single thread always so that the STA component is always launched on the same thread.
This isn't just one thread for all users, but one thread per user via the tracking session cookie.
Still - STA is very very inefficient for IIS to process.
If you run your same sample with multiple browsers (ie. separate sessions) then you should see the sleep not effect the other session.
+++ Rick ---
I'm using VS 2012/.NET 4.5 and experimenting with ASP.NET and FoxPro COM objects, trying to learn exactly how.NET/IIS handles associated threads. I have set AspCompat="true" in the page as directed. According to what I've read, requests are scheduled to an STA Thread Pool, but there is no explanation of how the thread pooling works. In my testing, it appears to be one thread per user session. If a user has two tabs open in their browser, these share the same session and hence the same thread. A running AspCompat request on one tab will block AspCompat requests on the second tab. For example, add a button to a web form and put the following code in the click event:
protectedvoid Button1_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(5000);
Response.Write("ASP.NET Thread " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
}
Be sure to set AspCompat ="true" in the page, then run the app and open the page in two tabs. Click the button on the first tab, then quickly switch to the second tab and click the button. You'll notice the first tab request has to complete before the second tab request starts, and afterwards the page reports that both requests ran on the same thread. Set AspCompat = "false" and rerun the tests. This time both requests run simultaneously and in different threads. At least this is what is happening in my tests.
Is this all by design? I know you need to use AspCompat for COM interop, but a user ought to be able to perform multiple tasks in multiple tabs like a normal web page, don't you think? Is there a configuration setting to modify this behavior?
Thanks,
Joel