Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>So my co-worker and I worked this out, finally, with a bunch of help from Reflector.</p> <p>The main problem is that HttpContext.Current is null when accessed via a remoting call.</p> <p>The HttpContext.Current property is stored in an interesting manor. A few nested setters down, you reach <code>CallContext.HostContext</code>. This is a static object property on a <code>CallContext</code>. </p> <p>When the CallContext is set, it first checks if the value is an <a href="http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.ilogicalthreadaffinative.aspx" rel="noreferrer"><code>ILogicalThreadAffinitive</code></a>.</p> <ul> <li>If it is, it stores the value in the current thread's <code>LogicalCallContext</code>.</li> <li>If it's not, it stores the value in the current thread's <code>IllogicalCallContext</code>.</li> </ul> <p><code>HttpContext</code> is <strong>not</strong> an <code>ILogicalThreadAffinitive</code>, so it is stored in the <code>IllogicalCallContext</code>.</p> <hr> <p><strong>Then, there's remoting.</strong> </p> <p>We didn't dig too far in to its source, but what it does was inferred from some other functions.</p> <p>When a call is made <em>to</em> a remote object <em>from</em> a different AppDomain, the call is not directly proxied to the original thread, running in the exact same execution context.</p> <p>First, the <code>ExecutionContext</code> of the original thread (the one containing <code>HttpContext.Current</code>) is captured, via <code>ExecutionContext.Capture</code> (more in this in a bit).</p> <p>Then, the <code>ExecutionContext</code> returned from <code>Capture</code> is passed as the first argument to <code>ExecutionContext.Run</code>, esentially forming the code:</p> <pre><code>Delegate myRemoteCall; //Assigned somewhere else in remoting ExecutionContext.Run(ExecutionContext.Capture(), x =&gt; { myRemoteCall() }, null); </code></pre> <p>Then, completely transparently, your code in the remote object is accessed.</p> <p>Unfortunately, <code>HttpContext.Current</code> is not captured in <code>ExecutionContext.Capture()</code>.</p> <p>Here lies the essential difference between an <code>IllogicalCallContext</code> and a <code>LogicalCallContext</code>. </p> <p><code>Capture</code> creates a brand-new <code>ExecutionContext</code>, essentially copying all of the members (such as the <code>LogicalCallContext</code>) in to the new object. But, it does <strong>not</strong> copy the <code>IllogicalCallContext</code>. </p> <p>So, since <code>HttpContext</code> is not an <code>ILogicalThreadAffinative</code>, it <em>cannot</em> be captured by <code>ExecutionContext.Capture</code>.</p> <hr> <p><strong>The solution?</strong></p> <p>HttpContext is not a MarshalByRefObject or [Serializable] (probably for good reason), so it cannot be passed in to the new AppDomain.</p> <p><strong>But</strong>, it can cross <code>ExecutionContext</code>s without problem. </p> <p>So, in the main AppDomain's MarshalByRefObject which is given as a proxy to the other AppDomain, in the constructor give it the instance of <code>HttpContext.Current</code>.</p> <p>Then, in each method call of the new object (unfortunately), run:</p> <pre><code>private HttpContext _context; private void SyncContext() { if(HttpContext.Current == null) HttpContext.Current = _context; } </code></pre> <p>And it will be set without problem. Since HttpContext.Current is tied to the <code>IllogicalCallContext</code> of the <code>ExecutionContext</code>, it will not bleed in to any other threads that ASP.NET might create, and will be cleaned up when the copy <code>ExecutionContext</code> is disposed.</p> <p>(I could be wrong about much of this, though. It's all speculation and reflection)</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload