You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -0,0 +1,134 @@
|
||||
namespace System.Web.Hosting {
|
||||
using System;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading;
|
||||
|
||||
// This HostExecutionContextManager can provide both setup and cleanup logic that
|
||||
// is invoked during a call to ExecutionContext.Run. This may be necessary when
|
||||
// using the Task-based APIs, as the 'await' language feature generally causes
|
||||
// this stack to be generated:
|
||||
//
|
||||
// { state machine callback }
|
||||
// ExecutionContext.Run
|
||||
// Task.SomeInternalCallback
|
||||
// AspNetSynchronizationContext.PostCallbackLogic
|
||||
//
|
||||
// The callback logic invoked by our AspNetSynchronizationContext.Post method puts
|
||||
// HttpContext-related information in the current ExecutionContext, but the
|
||||
// subsequent call to ExecutionContext.Run overwrites that information. So we have
|
||||
// logic in AspNetHostExecutionContextManager that can detect if a ThreadContext is
|
||||
// associated with the current thread (it will have been set by the Post callback),
|
||||
// and if so it should restore HttpContext.Current and other ExecutionContext-related
|
||||
// items on the current thread.
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
|
||||
internal sealed class AspNetHostExecutionContextManager : HostExecutionContextManager {
|
||||
|
||||
// Used as the return value from SetHostExecutionContext when our logic is active.
|
||||
// We use RevertAction instead of Action since it's unambiguous in the event that
|
||||
// base.SetHostExecutionContext itself ever changes to return Action.
|
||||
private delegate void RevertAction();
|
||||
|
||||
public override HostExecutionContext Capture() {
|
||||
ThreadContext currentContext = ThreadContext.Current;
|
||||
if (currentContext != null) {
|
||||
// We need to capture a reference to the current HttpContext's ThreadContextId
|
||||
// so that we can properly restore this instance on the call to SetHostExecutionContext.
|
||||
// See comment on HttpContext.ThreadContextId for more information.
|
||||
return new AspNetHostExecutionContext(
|
||||
baseContext: base.Capture(),
|
||||
httpContextThreadContextId: currentContext.HttpContext.ThreadContextId);
|
||||
}
|
||||
else {
|
||||
// There is no ThreadContext associated with this thread, hence there is no special
|
||||
// setup we need to do to restore things like HttpContext.Current. We can just
|
||||
// delegate to the base implementation.
|
||||
return base.Capture();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Revert(object previousState) {
|
||||
RevertAction revertAction = previousState as RevertAction;
|
||||
if (revertAction != null) {
|
||||
// Our revert logic should run. It will eventually call base.Revert.
|
||||
revertAction();
|
||||
}
|
||||
else {
|
||||
// We have no revert logic, so just call the base implementation.
|
||||
base.Revert(previousState);
|
||||
}
|
||||
}
|
||||
|
||||
public override object SetHostExecutionContext(HostExecutionContext hostExecutionContext) {
|
||||
AspNetHostExecutionContext castHostExecutionContext = hostExecutionContext as AspNetHostExecutionContext;
|
||||
if (castHostExecutionContext != null) {
|
||||
// Call base.SetHostExecutionContext before calling our own logic.
|
||||
object baseRevertParameter = null;
|
||||
if (castHostExecutionContext.BaseContext != null) {
|
||||
baseRevertParameter = base.SetHostExecutionContext(castHostExecutionContext.BaseContext);
|
||||
}
|
||||
|
||||
ThreadContext currentContext = ThreadContext.Current;
|
||||
if (currentContext != null && currentContext.HttpContext.ThreadContextId == castHostExecutionContext.HttpContextThreadContextId) {
|
||||
// If we reached this point, then 'castHostExecutionContext' was captured for the HttpContext
|
||||
// that is associated with the ThreadContext that is assigned to the current thread. We can
|
||||
// safely restore it.
|
||||
Action threadContextCleanupAction = currentContext.EnterExecutionContext();
|
||||
|
||||
// Perform cleanup in the opposite order from initialization.
|
||||
return (RevertAction)(() => {
|
||||
threadContextCleanupAction();
|
||||
if (baseRevertParameter != null) {
|
||||
base.Revert(baseRevertParameter);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
// If we reached this point, then 'castHostExecutionContext' was captured by us
|
||||
// but is not applicable to the current thread. This can happen if the developer
|
||||
// called ThreadPool.QueueUserWorkItem, for example. We don't restore HttpContext
|
||||
// on such threads since they're not under the control of ASP.NET. In this case,
|
||||
// we have already called base.SetHostExecutionContext, so we just need to return
|
||||
// the result of that function directly to our caller.
|
||||
return baseRevertParameter;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If we reached this point, then 'hostExecutionContext' was generated by our
|
||||
// base class instead of by us, so just delegate to the base implementation.
|
||||
return base.SetHostExecutionContext(hostExecutionContext);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class AspNetHostExecutionContext : HostExecutionContext {
|
||||
public readonly HostExecutionContext BaseContext;
|
||||
public readonly object HttpContextThreadContextId;
|
||||
|
||||
internal AspNetHostExecutionContext(HostExecutionContext baseContext, object httpContextThreadContextId) {
|
||||
BaseContext = baseContext;
|
||||
HttpContextThreadContextId = httpContextThreadContextId;
|
||||
}
|
||||
|
||||
// copy ctor
|
||||
private AspNetHostExecutionContext(AspNetHostExecutionContext original)
|
||||
: this(CreateCopyHelper(original.BaseContext), original.HttpContextThreadContextId) {
|
||||
}
|
||||
|
||||
public override HostExecutionContext CreateCopy() {
|
||||
return new AspNetHostExecutionContext(this);
|
||||
}
|
||||
|
||||
private static HostExecutionContext CreateCopyHelper(HostExecutionContext hostExecutionContext) {
|
||||
// creating a copy of a null context should just itself return null
|
||||
return (hostExecutionContext != null) ? hostExecutionContext.CreateCopy() : null;
|
||||
}
|
||||
|
||||
public override void Dispose(bool disposing) {
|
||||
if (disposing && BaseContext != null) {
|
||||
BaseContext.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user