Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@@ -0,0 +1,209 @@
//------------------------------------------------------------------------------
// <copyright file="AppDomainFactory.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
* AppDomain factory -- creates app domains on demand from ISAPI
*
* Copyright (c) 1999 Microsoft Corporation
*/
namespace System.Web.Hosting {
using System.Collections;
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Text;
using System.Web;
using System.Web.Compilation;
using System.Web.Util;
//
// IAppDomainFactory / AppDomainFactory are obsolete and stay public
// only to avoid breaking changes.
//
// The new code uses IAppManagerAppDomainFactory / AppAppManagerDomainFactory
//
/// <internalonly/>
[ComImport, Guid("e6e21054-a7dc-4378-877d-b7f4a2d7e8ba"), System.Runtime.InteropServices.InterfaceTypeAttribute(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)]
public interface IAppDomainFactory {
#if !FEATURE_PAL // FEATURE_PAL does not enable COM
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
[return: MarshalAs(UnmanagedType.Interface)]
Object Create(
[In, MarshalAs(UnmanagedType.BStr)]
String module,
[In, MarshalAs(UnmanagedType.BStr)]
String typeName,
[In, MarshalAs(UnmanagedType.BStr)]
String appId,
[In, MarshalAs(UnmanagedType.BStr)]
String appPath,
[In, MarshalAs(UnmanagedType.BStr)]
String strUrlOfAppOrigin,
[In, MarshalAs(UnmanagedType.I4)]
int iZone);
#else // !FEATURE_PAL
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)]
[return: MarshalAs(UnmanagedType.Error)]
Object Create(
[In, MarshalAs(UnmanagedType.Error)]
String module,
[In, MarshalAs(UnmanagedType.Error)]
String typeName,
[In, MarshalAs(UnmanagedType.Error)]
String appId,
[In, MarshalAs(UnmanagedType.Error)]
String appPath,
[In, MarshalAs(UnmanagedType.Error)]
String strUrlOfAppOrigin,
[In, MarshalAs(UnmanagedType.I4)]
int iZone);
#endif // FEATURE_PAL
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
/// <internalonly/>
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
public sealed class AppDomainFactory : IAppDomainFactory {
private AppManagerAppDomainFactory _realFactory;
public AppDomainFactory() {
_realFactory = new AppManagerAppDomainFactory();
}
/*
* Creates an app domain with an object inside
*/
#if !FEATURE_PAL // FEATURE_PAL does not enable COM
[return: MarshalAs(UnmanagedType.Interface)]
#endif // !FEATURE_PAL
public Object Create(String module, String typeName, String appId, String appPath,
String strUrlOfAppOrigin, int iZone) {
return _realFactory.Create(appId, appPath);
}
}
//
// The new code -- IAppManagerAppDomainFactory / AppAppManagerDomainFactory
//
/// <internalonly/>
[ComImport, Guid("02998279-7175-4d59-aa5a-fb8e44d4ca9d"), System.Runtime.InteropServices.InterfaceTypeAttribute(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)]
public interface IAppManagerAppDomainFactory {
#if !FEATURE_PAL // FEATURE_PAL does not enable COM
[return: MarshalAs(UnmanagedType.Interface)]
#else // !FEATURE_PAL
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)]
Object Create(String appId, String appPath);
#endif // !FEATURE_PAL
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
Object Create([In, MarshalAs(UnmanagedType.BStr)] String appId,
[In, MarshalAs(UnmanagedType.BStr)] String appPath);
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
void Stop();
}
/// <internalonly/>
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
public sealed class AppManagerAppDomainFactory : IAppManagerAppDomainFactory {
private ApplicationManager _appManager;
public AppManagerAppDomainFactory() {
_appManager = ApplicationManager.GetApplicationManager();
_appManager.Open();
}
/*
* Creates an app domain with an object inside
*/
#if FEATURE_PAL // FEATURE_PAL does not enable COM
[return: MarshalAs(UnmanagedType.Error)]
#else // FEATURE_PAL
[return: MarshalAs(UnmanagedType.Interface)]
#endif // FEATURE_PAL
public Object Create(String appId, String appPath) {
try {
//
// Fill app a Dictionary with 'binding rules' -- name value string pairs
// for app domain creation
//
//
if (appPath[0] == '.') {
System.IO.FileInfo file = new System.IO.FileInfo(appPath);
appPath = file.FullName;
}
if (!StringUtil.StringEndsWith(appPath, '\\')) {
appPath = appPath + "\\";
}
// Create new app domain via App Manager
#if FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
throw new NotImplementedException("ROTORTODO");
#else // FEATURE_PAL
ISAPIApplicationHost appHost = new ISAPIApplicationHost(appId, appPath, false /*validatePhysicalPath*/);
ISAPIRuntime isapiRuntime = (ISAPIRuntime)_appManager.CreateObjectInternal(appId, typeof(ISAPIRuntime), appHost,
false /*failIfExists*/, null /*hostingParameters*/);
isapiRuntime.StartProcessing();
return new ObjectHandle(isapiRuntime);
#endif // FEATURE_PAL
}
catch (Exception e) {
Debug.Trace("internal", "AppDomainFactory::Create failed with " + e.GetType().FullName + ": " + e.Message + "\r\n" + e.StackTrace);
throw;
}
}
public void Stop() {
// wait for all app domains to go away
_appManager.Close();
}
internal static String ConstructSimpleAppName(string virtPath) {
// devdiv 710164: Still repro - ctrl-f5 a WAP project might show "Cannot create/shadow copy when a file exists" error
// since the hash file lists are different, IISExpress launched by VS cannot reuse the build result from VS build.
// It deletes the build files generated by CBM and starts another round of build. This causes interruption between IISExpress and VS
// and leads to this shallow copy exception.
// fix: make the dev IISExpress build to a special drop location
if (virtPath.Length <= 1) { // root?
if (!BuildManagerHost.InClientBuildManager && HostingEnvironment.IsDevelopmentEnvironment)
return "vs";
else
return "root";
}
else
return virtPath.Substring(1).ToLower(CultureInfo.InvariantCulture).Replace('/', '_');
}
}
}

View File

@@ -0,0 +1,39 @@
//------------------------------------------------------------------------------
// <copyright file="AppDomainProtocolHandler.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System;
using System.Security.Permissions;
public abstract class AppDomainProtocolHandler : MarshalByRefObject, IRegisteredObject {
protected AppDomainProtocolHandler() {
HostingEnvironment.RegisterObject(this);
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
public override Object InitializeLifetimeService(){
return null; // never expire lease
}
public abstract void StartListenerChannel(IListenerChannelCallback listenerChannelCallback);
public abstract void StopListenerChannel(int listenerChannelId, bool immediate);
public abstract void StopProtocol(bool immediate);
public virtual void Stop(bool immediate) {
StopProtocol(true);
HostingEnvironment.UnregisterObject(this);
}
}
}

View File

@@ -0,0 +1,60 @@
//------------------------------------------------------------------------------
// <copyright file="ApplicationHost.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System;
using System.IO;
using System.Collections;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using System.Web;
using System.Web.Configuration;
using System.Web.Util;
using System.Security.Permissions;
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public sealed class ApplicationHost {
private ApplicationHost() {
}
/*
* Creates new app domain for hosting of ASP.NET apps with a
* user defined 'host' object in it. The host is needed to make
* cross-domain calls to process requests in the host's app domain
*/
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
public static Object CreateApplicationHost(Type hostType, String virtualDir, String physicalDir) {
#if !FEATURE_PAL // FEATURE_PAL does not require PlatformID.Win32NT
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
throw new PlatformNotSupportedException(SR.GetString(SR.RequiresNT));
#else // !FEATURE_PAL
// FEATURE_PAL
#endif // !FEATURE_PAL
if (!StringUtil.StringEndsWith(physicalDir, Path.DirectorySeparatorChar))
physicalDir = physicalDir + Path.DirectorySeparatorChar;
ApplicationManager appManager = ApplicationManager.GetApplicationManager();
String appId = (String.Concat(virtualDir, physicalDir).GetHashCode()).ToString("x");
ObjectHandle h = appManager.CreateInstanceInNewWorkerAppDomain(
hostType, appId, VirtualPath.CreateNonRelative(virtualDir), physicalDir);
return h.Unwrap();
}
}
}

View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
// <copyright file="ApplicationInfo.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System;
using System.Security.Permissions;
[Serializable]
public sealed class ApplicationInfo {
private string _id;
private VirtualPath _virtualPath;
private string _physicalPath;
internal ApplicationInfo(string id, VirtualPath virtualPath, string physicalPath) {
_id = id;
_virtualPath = virtualPath;
_physicalPath = physicalPath;
}
public String ID {
get { return _id; }
}
public String VirtualPath {
get { return _virtualPath.VirtualPathString; }
}
public String PhysicalPath {
get { return _physicalPath; }
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -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();
}
}
}
}
}

View File

@@ -0,0 +1,103 @@
//------------------------------------------------------------------------------
// <copyright file="AsyncResultBase.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
* IAsyncResult for asynchronous reads.
*
* Copyright (c) 2010 Microsoft Corporation
*/
namespace System.Web.Hosting {
using System;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Web.Util;
internal abstract class AsyncResultBase : IAsyncResult {
private ManualResetEventSlim _mre; // unlike ManualResetEvent, this creates a kernel object lazily
private AsyncCallback _callback;
private Object _asyncState;
private volatile bool _completed;
private volatile bool _completedSynchronously;
private volatile int _hresult;
private Thread _threadWhichStartedOperation;
private volatile ExceptionDispatchInfo _error;
protected AsyncResultBase(AsyncCallback cb, Object state) {
_callback = cb;
_asyncState = state;
_mre = new ManualResetEventSlim();
}
internal abstract void Complete(int bytesCompleted, int hresult, IntPtr pAsyncCompletionContext, bool synchronous);
protected void Complete(int hresult, bool synchronous) {
if (Volatile.Read(ref _threadWhichStartedOperation) == Thread.CurrentThread) {
// If we're calling Complete on the same thread which kicked off the operation, then
// we ignore the 'synchronous' value that the caller provided to us since we know
// for a fact that this is really a synchronous completion. This is only checked if
// the caller calls the MarkCallToBeginMethod* routines below, which only occurs in
// the Classic Mode pipeline.
synchronous = true;
}
_hresult = hresult;
_completed = true;
_completedSynchronously = synchronous;
_mre.Set();
if (_callback != null)
_callback(this);
}
// If the caller needs to invoke an asynchronous method where the only way of knowing whether the
// method actually completed synchronously is to inspect which thread the callback was invoked on,
// then the caller should surround the asynchronous call with calls to the below Started / Completed
// methods. The callback can compare the captured thread against the current thread to see if the
// completion was synchronous. The caller calls the Completed method when unwinding so that the
// captured thread can be cleared out, preventing an asynchronous invocation on the same thread
// from being mistaken for a synchronous invocation.
internal void MarkCallToBeginMethodStarted() {
Thread originalThread = Interlocked.CompareExchange(ref _threadWhichStartedOperation, Thread.CurrentThread, null);
Debug.Assert(originalThread == null, "Another thread already called MarkCallToBeginMethodStarted.");
}
internal void MarkCallToBeginMethodCompleted() {
Thread originalThread = Interlocked.Exchange(ref _threadWhichStartedOperation, null);
Debug.Assert(originalThread == Thread.CurrentThread, "This thread did not call MarkCallToBeginMethodStarted.");
}
internal void ReleaseWaitHandleWhenSignaled() {
try {
_mre.Wait();
}
finally {
_mre.Dispose();
}
}
internal void SetError(Exception error) {
Debug.Assert(error != null);
_error = ExceptionDispatchInfo.Capture(error);
}
// Properties that are not part of IAsyncResult
//
internal int HResult { get { return _hresult; } set { _hresult = value; } }
internal ExceptionDispatchInfo Error { get { return _error; } }
//
// IAsyncResult implementation
//
public bool IsCompleted { get { return _completed; } }
public bool CompletedSynchronously { get { return _completedSynchronously; } }
public Object AsyncState { get { return _asyncState; } }
public WaitHandle AsyncWaitHandle { get { return _mre.WaitHandle; } } // wait not supported
}
}

View File

@@ -0,0 +1,114 @@
//------------------------------------------------------------------------------
// <copyright file="BackgroundWorkScheduler.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Util;
internal sealed class BackgroundWorkScheduler : IRegisteredObject {
private readonly CancellationTokenHelper _cancellationTokenHelper = new CancellationTokenHelper(canceled: false);
private int _numExecutingWorkItems; // number of executing work items, not scheduled work items; a work item might never be scheduled
private readonly Action<BackgroundWorkScheduler> _unregisterCallback;
private readonly Action<AppDomain, Exception> _logCallback;
private readonly Action _workItemCompleteCallback;
internal BackgroundWorkScheduler(Action<BackgroundWorkScheduler> unregisterCallback, Action<AppDomain, Exception> logCallback, Action workItemCompleteCallback = null) {
Debug.Assert(unregisterCallback != null);
_unregisterCallback = unregisterCallback;
_logCallback = logCallback;
_workItemCompleteCallback = workItemCompleteCallback;
}
private void FinalShutdown() {
_unregisterCallback(this);
}
// we can use 'async void' here since we're guaranteed to be off the AspNetSynchronizationContext
private async void RunWorkItemImpl(Func<CancellationToken, Task> workItem) {
Task returnedTask = null;
try {
returnedTask = workItem(_cancellationTokenHelper.Token);
await returnedTask.ConfigureAwait(continueOnCapturedContext: false);
}
catch (Exception ex) {
// ---- exceptions caused by the returned task being canceled
if (returnedTask != null && returnedTask.IsCanceled) {
return;
}
// ---- exceptions caused by CancellationToken.ThrowIfCancellationRequested()
OperationCanceledException operationCanceledException = ex as OperationCanceledException;
if (operationCanceledException != null && operationCanceledException.CancellationToken == _cancellationTokenHelper.Token) {
return;
}
_logCallback(AppDomain.CurrentDomain, ex); // method shouldn't throw
}
finally {
WorkItemComplete();
}
}
public void ScheduleWorkItem(Func<CancellationToken, Task> workItem) {
Debug.Assert(workItem != null);
if (_cancellationTokenHelper.IsCancellationRequested) {
return; // we're not going to run this work item
}
// Unsafe* since we want to get rid of Principal and other constructs specific to the current ExecutionContext
ThreadPool.UnsafeQueueUserWorkItem(state => {
lock (this) {
if (_cancellationTokenHelper.IsCancellationRequested) {
return; // we're not going to run this work item
}
else {
_numExecutingWorkItems++;
}
}
RunWorkItemImpl((Func<CancellationToken, Task>)state);
}, workItem);
}
public void Stop(bool immediate) {
// Hold the lock for as little time as possible
int currentWorkItemCount;
lock (this) {
_cancellationTokenHelper.Cancel(); // dispatched onto a new thread
currentWorkItemCount = _numExecutingWorkItems;
}
if (currentWorkItemCount == 0) {
// There was no scheduled work, so we're done
FinalShutdown();
}
}
private void WorkItemComplete() {
// Hold the lock for as little time as possible
int newWorkItemCount;
bool isCancellationRequested;
lock (this) {
newWorkItemCount = --_numExecutingWorkItems;
isCancellationRequested = _cancellationTokenHelper.IsCancellationRequested;
}
// for debugging & unit tests
if (_workItemCompleteCallback != null) {
_workItemCompleteCallback();
}
if (newWorkItemCount == 0 && isCancellationRequested) {
// Cancellation was requested, and we were the last work item to complete, so everybody is finished
FinalShutdown();
}
}
}
}

View File

@@ -0,0 +1,420 @@
using System;
using System.Globalization;
using System.Web;
using System.Web.Util;
using System.Threading;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Debug = System.Web.Util.Debug;
//
// Welcome to the CacheManager class, CM for short. CM monitors private bytes for the
// worker process. If the Private Bytes limit is about to be exceeded, CM will trim
// the cache (as necessary), and induce a GC to prevent the process from recycling.
//
// A timer thread is used to monitor Private Bytes. The interval is adjusted depending
// on the current memory pressure. The maximum interval is every 2 minutes, and the
// minimum interval is every 5 seconds.
//
namespace System.Web.Hosting {
internal class CacheManager: IDisposable {
const int HIGH_FREQ_INTERVAL_S = 5;
const int HIGH_FREQ_INTERVAL_MS = 5 * Msec.ONE_SECOND;
const int MEDIUM_FREQ_INTERVAL_S = 30;
const int MEDIUM_FREQ_INTERVAL_MS = 30 * Msec.ONE_SECOND;
const int LOW_FREQ_INTERVAL_S = 120;
const int LOW_FREQ_INTERVAL_MS = 120 * Msec.ONE_SECOND;
const int MEGABYTE_SHIFT = 20;
const long MEGABYTE = 1L << MEGABYTE_SHIFT; // 1048576
const int SAMPLE_COUNT = 2;
const int DELTA_SAMPLE_COUNT = 10;
private ApplicationManager _appManager;
private long _totalCacheSize;
private long _trimDurationTicks;
private int _lastTrimPercent = 10; // starts at 10, but changes to fit workload
private long _inducedGCMinInterval = TimeSpan.TicksPerSecond * 5; // starts at 5 seconds, but changes to fit workload
private DateTime _inducedGCFinishTime = DateTime.MinValue;
private long _inducedGCDurationTicks;
private int _inducedGCCount;
private long _inducedGCPostPrivateBytes;
private long _inducedGCPrivateBytesChange;
private int _currentPollInterval = MEDIUM_FREQ_INTERVAL_MS;
private DateTime _timerSuspendTime = DateTime.MinValue;
private int _inPBytesMonitorThread;
private Timer _timer;
private Object _timerLock = new object();
private long _limit; // the "effective" worker process Private Bytes limit
private long _highPressureMark;
private long _mediumPressureMark;
private long _lowPressureMark;
private long[] _deltaSamples; // a history of the increase in private bytes per second
private int _idxDeltaSamples;
private long _maxDelta; // the maximum expected increase in private bytes per second
private long _minMaxDelta; // _maxDelta must always be at least this large
private long[] _samples; // a history of the sample values (private bytes for the process)
private DateTime[] _sampleTimes; // time at which samples were taken
private int _idx;
private bool _useGetProcessMemoryInfo;
private uint _pid;
private bool _disposed;
private CacheManager() {}
internal CacheManager(ApplicationManager appManager, long privateBytesLimit) {
#if PERF
SafeNativeMethods.OutputDebugString(String.Format("Creating CacheManager with PrivateBytesLimit = {0:N}\n", privateBytesLimit));
#endif
// don't create timer if there's no memory limit
if (privateBytesLimit <= 0) {
return;
}
_appManager = appManager;
_limit = privateBytesLimit;
_pid = (uint) SafeNativeMethods.GetCurrentProcessId();
// the initial expected maximum increase in private bytes is 2MB per second per CPU
_minMaxDelta = 2 * MEGABYTE * SystemInfo.GetNumProcessCPUs();
AdjustMaxDeltaAndPressureMarks(_minMaxDelta);
_samples = new long[SAMPLE_COUNT];
_sampleTimes = new DateTime[SAMPLE_COUNT];
_useGetProcessMemoryInfo = (VersionInfo.ExeName == "w3wp");
_deltaSamples = new long[DELTA_SAMPLE_COUNT];
// start timer with initial poll interval
_timer = new Timer(new TimerCallback(this.PBytesMonitorThread), null, _currentPollInterval, _currentPollInterval);
}
void Adjust() {
// not thread-safe, only invoke from timer callback
Debug.Assert(_inPBytesMonitorThread == 1);
Debug.Assert(SAMPLE_COUNT == 2);
// current sample
long s2 = _samples[_idx];
// previous sample
long s1 = _samples[_idx ^ 1];
// adjust _maxDelta and pressure marks
if (s2 > s1 && s1 > 0) {
// current time
DateTime d2 = _sampleTimes[_idx];
// previous time
DateTime d1 = _sampleTimes[_idx ^ 1];
long numBytes = s2 - s1;
long numSeconds = (long)Math.Round(d2.Subtract(d1).TotalSeconds);
if (numSeconds > 0) {
long delta = numBytes / numSeconds;
_deltaSamples[_idxDeltaSamples] = delta;
_idxDeltaSamples = (_idxDeltaSamples + 1) % DELTA_SAMPLE_COUNT;
// update rate of change in private bytes and pressure marks
AdjustMaxDeltaAndPressureMarks(delta);
}
}
lock (_timerLock) {
if (_timer == null) {
return;
}
// adjust timer frequency
if (s2 > _mediumPressureMark) {
if (_currentPollInterval > HIGH_FREQ_INTERVAL_MS) {
_currentPollInterval = HIGH_FREQ_INTERVAL_MS;
_timer.Change(_currentPollInterval, _currentPollInterval);
}
}
else if (s2 > _lowPressureMark) {
if (_currentPollInterval > MEDIUM_FREQ_INTERVAL_MS) {
_currentPollInterval = MEDIUM_FREQ_INTERVAL_MS;
_timer.Change(_currentPollInterval, _currentPollInterval);
}
}
else {
if (_currentPollInterval != LOW_FREQ_INTERVAL_MS) {
_currentPollInterval = LOW_FREQ_INTERVAL_MS;
_timer.Change(_currentPollInterval, _currentPollInterval);
}
}
}
}
void AdjustMaxDeltaAndPressureMarks(long delta) {
// not thread-safe...only invoke from ctor or timer callback
Debug.Assert(_inPBytesMonitorThread == 1 || _timer == null);
// The value of _maxDelta is the largest rate of change we've seen,
// but it is reduced if the rate is now consistently less than what
// it once was.
long newMaxDelta = _maxDelta;
if (delta > newMaxDelta) {
// set maxDelta to the current rate of change
newMaxDelta = delta;
}
else {
// if _maxDelta is at least four times larger than every sample rate in the history,
// then reduce _maxDelta
bool reduce = true;
long maxDelta = _maxDelta / 4;
foreach (long rate in _deltaSamples) {
if (rate > maxDelta) {
reduce = false;
break;
}
}
if (reduce) {
newMaxDelta = maxDelta * 2;
}
}
// ensure that maxDelta is sufficiently large so that the _highPressureMark is sufficiently
// far away from the memory limit
newMaxDelta = Math.Max(newMaxDelta, _minMaxDelta);
// Do we have a new maxDelta? If so, adjust it and pressure marks.
if (_maxDelta != newMaxDelta) {
// adjust _maxDelta
_maxDelta = newMaxDelta;
// instead of using _maxDelta, use twice _maxDelta since recycling is
// expensive and the real delta fluctuates
_highPressureMark = Math.Max(_limit * 9 / 10, _limit - (_maxDelta * 2 * HIGH_FREQ_INTERVAL_S));
_lowPressureMark = Math.Max(_limit * 6 / 10, _limit - (_maxDelta * 2 * LOW_FREQ_INTERVAL_S));
_mediumPressureMark = Math.Max((_highPressureMark + _lowPressureMark) / 2 , _limit - (_maxDelta * 2 * MEDIUM_FREQ_INTERVAL_S));
_mediumPressureMark = Math.Min(_highPressureMark , _mediumPressureMark);
#if PERF
SafeNativeMethods.OutputDebugString(String.Format("CacheManager.AdjustMaxDeltaAndPressureMarks: _highPressureMark={0:N}, _mediumPressureMark={1:N}, _lowPressureMark={2:N}, _maxDelta={3:N}\n", _highPressureMark, _mediumPressureMark, _lowPressureMark, _maxDelta));
#endif
#if DBG
Debug.Trace("CacheMemory", "AdjustMaxDeltaAndPressureMarks "
+ "delta=" + delta
+ ", _maxDelta=" + _maxDelta
+ ", _highPressureMark=" + _highPressureMark
+ ", _mediumPressureMark=" + _mediumPressureMark
+ ", _lowPressureMark=" + _lowPressureMark);
#endif
}
}
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", Justification="Need to call GC.Collect.")]
private void CollectInfrequently(long privateBytes) {
// not thread-safe, only invoke from timer callback
Debug.Assert(_inPBytesMonitorThread == 1);
// The Server GC on x86 can traverse ~200mb per CPU per second, and the maximum heap size
// is about 3400mb, so the worst case scenario on x86 would take about 8 seconds to collect
// on a dual CPU box.
//
// The Server GC on x64 can traverse ~300mb per CPU per second, so a 6000 MB heap will take
// about 10 seconds to collect on a dual CPU box. The worst case scenario on x64 would make
// you want to return your hardware for a refund.
long timeSinceInducedGC = DateTime.UtcNow.Subtract(_inducedGCFinishTime).Ticks;
bool infrequent = (timeSinceInducedGC > _inducedGCMinInterval);
// if we haven't collected recently, or if the trim percent is low (less than 50%),
// we need to collect again
if (infrequent || _lastTrimPercent < 50) {
// if we're inducing GC too frequently, increase the trim percentage, but don't go above 50%
if (!infrequent) {
_lastTrimPercent = Math.Min(50, _lastTrimPercent + 10);
}
// if we're inducing GC infrequently, we may want to decrease the trim percentage
else if (_lastTrimPercent > 10 && timeSinceInducedGC > 2 * _inducedGCMinInterval) {
_lastTrimPercent = Math.Max(10, _lastTrimPercent - 10);
}
int percent = (_totalCacheSize > 0) ? _lastTrimPercent : 0;
long trimmedOrExpired = 0;
if (percent > 0) {
Stopwatch sw1 = Stopwatch.StartNew();
trimmedOrExpired = _appManager.TrimCaches(percent);
sw1.Stop();
_trimDurationTicks = sw1.Elapsed.Ticks;
}
//
if (trimmedOrExpired == 0 || _appManager.ShutdownInProgress) {
return;
}
// collect and record statistics
Stopwatch sw2 = Stopwatch.StartNew();
GC.Collect();
sw2.Stop();
_inducedGCCount++; // only used for debugging
_inducedGCFinishTime = DateTime.UtcNow;
_inducedGCDurationTicks = sw2.Elapsed.Ticks;
_inducedGCPostPrivateBytes = NextSample();
_inducedGCPrivateBytesChange = privateBytes - _inducedGCPostPrivateBytes;
// target 3.3% Time in GC, but don't induce a GC more than once every 5 seconds
// Notes on calculation below: If G is duration of garbage collection and T is duration
// between starting the next collection, then G/T is % Time in GC. If we target 3.3%,
// then G/T = 3.3% = 33/1000, so T = G * 1000/33.
_inducedGCMinInterval = Math.Max(_inducedGCDurationTicks * 1000 / 33, 5 * TimeSpan.TicksPerSecond);
// no more frequently than every 60 seconds if change is less than 1%
if (_inducedGCPrivateBytesChange * 100 <= privateBytes) {
_inducedGCMinInterval = Math.Max(_inducedGCMinInterval, 60 * TimeSpan.TicksPerSecond);
}
#if DBG
Debug.Trace("CacheMemory", "GC.COLLECT STATS "
+ "TrimCaches(" + percent + ")"
+ ", trimDurationSeconds=" + (_trimDurationTicks/TimeSpan.TicksPerSecond)
+ ", trimmedOrExpired=" + trimmedOrExpired
+ ", #secondsSinceInducedGC=" + (timeSinceInducedGC/TimeSpan.TicksPerSecond)
+ ", InducedGCCount=" + _inducedGCCount
+ ", gcDurationSeconds=" + (_inducedGCDurationTicks/TimeSpan.TicksPerSecond)
+ ", PrePrivateBytes=" + privateBytes
+ ", PostPrivateBytes=" + _inducedGCPostPrivateBytes
+ ", PrivateBytesChange=" + _inducedGCPrivateBytesChange
+ ", gcMinIntervalSeconds=" + (_inducedGCMinInterval/TimeSpan.TicksPerSecond));
#endif
#if PERF
SafeNativeMethods.OutputDebugString(" ** COLLECT **: "
+ percent + "%, "
+ (_trimDurationTicks/TimeSpan.TicksPerSecond) + " seconds"
+ ", infrequent=" + infrequent
+ ", removed=" + trimmedOrExpired
+ ", sinceIGC=" + (timeSinceInducedGC/TimeSpan.TicksPerSecond)
+ ", IGCCount=" + _inducedGCCount
+ ", IGCDuration=" + (_inducedGCDurationTicks/TimeSpan.TicksPerSecond)
+ ", preBytes=" + privateBytes
+ ", postBytes=" + _inducedGCPostPrivateBytes
+ ", byteChange=" + _inducedGCPrivateBytesChange
+ ", IGCMinInterval=" + (_inducedGCMinInterval/TimeSpan.TicksPerSecond) + "\n");
#endif
}
}
internal long GetUpdatedTotalCacheSize(long sizeUpdate) {
if (sizeUpdate != 0) {
long totalSize = Interlocked.Add(ref _totalCacheSize, sizeUpdate);
#if PERF
SafeNativeMethods.OutputDebugString("CacheManager.GetUpdatedTotalCacheSize:"
+ " _totalCacheSize= " + totalSize
+ ", sizeUpdate=" + sizeUpdate + "\n");
#endif
return totalSize;
}
else {
return _totalCacheSize;
}
}
public void Dispose() {
_disposed = true;
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
// managed and unmanaged resources can be touched/released
DisposeTimer();
}
else {
// the finalizer is calling, so don't touch managed state
}
}
private void DisposeTimer() {
lock (_timerLock) {
if (_timer != null) {
_timer.Dispose();
_timer = null;
}
}
}
private void PBytesMonitorThread(object state) {
// callbacks are queued and can unleash all at once, so concurrent invocations must be prevented
if (Interlocked.Exchange(ref _inPBytesMonitorThread, 1) != 0)
return;
try {
if (_disposed) {
return;
}
#if DBG
Debug.Trace("CacheMemory", "\r\n\r\n***BEG** PBytesMonitorThread " + DateTime.Now.ToString("T", CultureInfo.InvariantCulture));
#endif
// get another sample
long privateBytes = NextSample();
// adjust frequency of timer and pressure marks after the sample is captured
Adjust();
if (privateBytes > _highPressureMark) {
// induce a GC if necessary
CollectInfrequently(privateBytes);
}
#if DBG
Debug.Trace("CacheMemory", "**END** PBytesMonitorThread "
+ "privateBytes=" + privateBytes
+ ", _highPressureMark=" + _highPressureMark);
#endif
}
finally {
Interlocked.Exchange(ref _inPBytesMonitorThread, 0);
}
}
private long NextSample() {
// not thread-safe, only invoke from timer callback
Debug.Assert(_inPBytesMonitorThread == 1);
// NtQuerySystemInformation is a very expensive call. A new function
// exists on XP Pro and later versions of the OS and it performs much
// better. The name of that function is GetProcessMemoryInfo. For hosting
// scenarios where a larger number of w3wp.exe instances are running, we
// want to use the new API (VSWhidbey 417366).
long privateBytes;
if (_useGetProcessMemoryInfo) {
long privatePageCount;
UnsafeNativeMethods.GetPrivateBytesIIS6(out privatePageCount, true /*nocache*/);
privateBytes = privatePageCount;
}
else {
uint dummy;
uint privatePageCount = 0;
// this is a very expensive call
UnsafeNativeMethods.GetProcessMemoryInformation(_pid, out privatePageCount, out dummy, true /*nocache*/);
privateBytes = (long)privatePageCount << MEGABYTE_SHIFT;
}
// increment the index (it's either 1 or 0)
Debug.Assert(SAMPLE_COUNT == 2);
_idx = _idx ^ 1;
// remember the sample time
_sampleTimes[_idx] = DateTime.UtcNow;
// remember the sample value
_samples[_idx] = privateBytes;
#if PERF
SafeNativeMethods.OutputDebugString(String.Format("CacheManager.NextSample: privateBytes={0:N}, _highPresureMark={1:N}\n", privateBytes, _highPressureMark));
#endif
return privateBytes;
}
}
}

View File

@@ -0,0 +1,36 @@
//------------------------------------------------------------------------------
// <copyright file="ApplicatonManager.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System.Web;
using System.Web.Configuration;
using System.Runtime.Remoting.Messaging;
using System.Security.Permissions;
internal class ContextBase {
internal static Object Current {
get {
return CallContext.HostContext;
}
[SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
set {
CallContext.HostContext = value;
}
}
// static methods
internal static Object SwitchContext(Object newContext) {
Object oldContext = CallContext.HostContext;
if (oldContext != newContext)
CallContext.HostContext = newContext;
return oldContext;
}
}
}

View File

@@ -0,0 +1,95 @@
//------------------------------------------------------------------------------
// <copyright file="CustomRuntimeSuspendManager.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Web.Util;
// Handles calling suspend and resume methods, including issues around
// synchronization and timeout handling.
internal sealed class CustomRuntimeManager : ICustomRuntimeManager {
private readonly ConcurrentDictionary<CustomRuntimeRegistration, object> _activeRegistrations = new ConcurrentDictionary<CustomRuntimeRegistration, object>();
private List<IProcessSuspendListener> GetAllSuspendListeners() {
List<IProcessSuspendListener> suspendListeners = new List<IProcessSuspendListener>();
foreach (var registration in _activeRegistrations.Keys) {
var suspendListener = registration.CustomRuntime as IProcessSuspendListener;
if (suspendListener != null) {
suspendListeners.Add(suspendListener);
}
}
return suspendListeners;
}
public ICustomRuntimeRegistrationToken Register(ICustomRuntime customRuntime) {
CustomRuntimeRegistration registration = new CustomRuntimeRegistration(this, customRuntime);
_activeRegistrations[registration] = null;
return registration;
}
// Custom runtimes are expected to be well-behaved so will be suspended sequentially and aren't
// subject to the 5-second timeout that normal applications are subject to.
public Action SuspendAllCustomRuntimes() {
var suspendListeners = GetAllSuspendListeners();
if (suspendListeners == null || suspendListeners.Count == 0) {
return null;
}
List<IProcessResumeCallback> callbacks = new List<IProcessResumeCallback>(suspendListeners.Count);
foreach (var suspendListener in suspendListeners) {
IProcessResumeCallback callback = null;
try {
callback = suspendListener.Suspend();
}
catch (AppDomainUnloadedException) {
// There exists a race condition where a custom runtime could have been stopped (unloaded)
// while a call to Suspend is in progress, so AD unloads may leak out. Don't treat this
// as a failure; just move on.
}
if (callback != null) {
callbacks.Add(callback);
}
}
return () => {
foreach (var callback in callbacks) {
try {
callback.Resume();
}
catch (AppDomainUnloadedException) {
// There exists a race condition where a custom runtime could have been stopped (unloaded)
// while a call to Suspend is in progress, so AD unloads may leak out. Don't treat this
// as a failure; just move on.
}
}
};
}
private sealed class CustomRuntimeRegistration : ICustomRuntimeRegistrationToken {
private readonly CustomRuntimeManager _customRuntimeManager;
public CustomRuntimeRegistration(CustomRuntimeManager customRuntimeManager, ICustomRuntime customRuntime) {
_customRuntimeManager = customRuntimeManager;
CustomRuntime = customRuntime;
}
public ICustomRuntime CustomRuntime { get; private set; }
public void Unregister() {
object dummy;
bool removed = _customRuntimeManager._activeRegistrations.TryRemove(this, out dummy);
Debug.Assert(removed, "Entry did not exist in the dictionary; was it removed twice?");
}
}
}
}

View File

@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <copyright file="FlushAsyncResult.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
* IAsyncResult for asynchronous flush.
*
* Copyright (c) 2010 Microsoft Corporation
*/
namespace System.Web.Hosting {
using System;
using System.Threading;
using System.Web.Util;
internal class FlushAsyncResult : AsyncResultBase {
internal FlushAsyncResult(AsyncCallback cb, Object state): base(cb, state) {
}
internal override void Complete(int bytesSent, int hresult, IntPtr pAsyncCompletionContext, bool synchronous) {
Complete(hresult, synchronous);
}
}
}

View File

@@ -0,0 +1,29 @@
//------------------------------------------------------------------------------
// <copyright file="HTTP_COOKED_URL.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System;
using System.Runtime.InteropServices;
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa364519.aspx
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct HTTP_COOKED_URL {
// WARNING: Lengths are specified in bytes, not wide chars!
// Length does not include a null terminator.
internal readonly ushort FullUrlLength;
internal readonly ushort HostLength;
internal readonly ushort AbsPathLength;
internal readonly ushort QueryStringLength;
// WARNING: pFullUrl is the only string guaranteed by HTTP.SYS
// to be null-terminated (though see comment above re: length).
// Other fields point within pFullUrl so may not be null-terinated.
internal readonly char* pFullUrl;
internal readonly char* pHost;
internal readonly char* pAbsPath;
internal readonly char* pQueryString;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,35 @@
//------------------------------------------------------------------------------
// <copyright file="HostingEnvironmentException.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System;
using System.Runtime.Serialization;
using System.Security.Permissions;
[Serializable]
internal class HostingEnvironmentException : Exception {
private String _details;
protected HostingEnvironmentException(SerializationInfo info, StreamingContext context) : base(info, context) {
_details = info.GetString("_details");
}
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context) {
base.GetObjectData(info, context);
info.AddValue("_details", _details);
}
internal HostingEnvironmentException(String message, String details) : base(message) {
_details = details;
}
internal String Details {
get { return (_details != null) ? _details : String.Empty; }
}
}
}

View File

@@ -0,0 +1,48 @@
//------------------------------------------------------------------------------
// <copyright file="ApplicationManager.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System;
using System.Collections;
using System.Configuration;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Web;
using System.Web.Configuration;
using System.Web.Util;
public interface IApplicationHost {
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
[SecurityPermission(SecurityAction.InheritanceDemand, Unrestricted = true)]
string GetVirtualPath();
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
[SecurityPermission(SecurityAction.InheritanceDemand, Unrestricted = true)]
String GetPhysicalPath();
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
[SecurityPermission(SecurityAction.InheritanceDemand, Unrestricted = true)]
IConfigMapPathFactory GetConfigMapPathFactory();
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
[SecurityPermission(SecurityAction.InheritanceDemand, Unrestricted = true)]
IntPtr GetConfigToken();
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
[SecurityPermission(SecurityAction.InheritanceDemand, Unrestricted = true)]
String GetSiteName();
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
[SecurityPermission(SecurityAction.InheritanceDemand, Unrestricted = true)]
String GetSiteID();
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
[SecurityPermission(SecurityAction.InheritanceDemand, Unrestricted = true)]
void MessageReceived();
}
}

View File

@@ -0,0 +1,46 @@
//------------------------------------------------------------------------------
// <copyright file="ICustomLoader.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
/*
* !! USAGE NOTE !!
* This interface is not exposed publicly because it is expected that Helios developers will consume the
* no-PIA interfaces that will be released OOB. This interface only exists so that ASP.NET can interface
* with the Helios layer if necessary. These interfaces are subject to change.
*/
/// <summary>
/// Defines the entry point where the Helios hoster calls into the developer-provided bootstrapper.
/// The developer's bin-deployed AspNet.Loader assembly is expected to have an assembly-level
/// CustomLoaderAttribute whose ctor parameter is a type which implements this interface.
/// </summary>
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("50A3CE65-2F9F-44E9-9094-32C6C928F966")]
internal interface ICustomLoader {
/// <summary>
/// Loads a custom runtime for the current application.
/// </summary>
/// <param name="appId">The ID of the current application (e.g., IHttpApplication::GetApplicationId).</param>
/// <param name="appConfigPath">The configuration path of the current application (e.g., IHttpApplication::GetAppConfigPath).</param>
/// <param name="supportFunctions">Support functions for the current host.</param>
/// <param name="pLoadAppData">Additional data that may be useful to a custom loader for integrating with the IIS pipeline.
/// This pointer is only valid within the call to LoadApplication.</param>
/// <param name="loadAppDataSize">The size (in bytes) of the structure pointed to by pLoadAppData.</param>
/// <returns>An ICustomRuntime instance wrapped inside an ObjectHandle.</returns>
[return: MarshalAs(UnmanagedType.Interface)]
IObjectHandle LoadApplication(
[In, MarshalAs(UnmanagedType.LPWStr)] string appId,
[In, MarshalAs(UnmanagedType.LPWStr)] string appConfigPath,
[In, MarshalAs(UnmanagedType.Interface)] IProcessHostSupportFunctions supportFunctions,
[In] IntPtr pLoadAppData,
[In] int loadAppDataSize);
}
}

View File

@@ -0,0 +1,59 @@
//------------------------------------------------------------------------------
// <copyright file="ICustomRuntime.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
/*
* !! USAGE NOTE !!
* This interface is not exposed publicly because it is expected that Helios developers will consume the
* no-PIA interfaces that will be released OOB. This interface only exists so that ASP.NET can interface
* with the Helios layer if necessary. These interfaces are subject to change.
*/
/// <summary>
/// Defines the mechanism via which IIS will interact with the application.
/// </summary>
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("692D0723-C338-4D09-9057-C71F0F47DA87")]
internal interface ICustomRuntime {
/// <summary>
/// Called at some point between GL_APPLICATION_START and
/// GL_RESOLVE_MODULES and signals managed application start.
/// </summary>
/// <param name="reserved0">Do not use this parameter.</param>
/// <param name="reserved1">Do not use this parameter.</param>
void Start(
[In] IntPtr reserved0,
[In] int reserved1);
/// <summary>
/// Called during GL_RESOLVE_MODULES to give managed runtime a
/// chance to register CHttpModule instances with the IIS pipeline.
/// </summary>
/// <param name="pResolveModuleData">Additional data that may be useful to the custom runtime for integrating with the IIS pipeline.
/// This pointer is only valid within the call to ResolveModules.</param>
/// <param name="resolveModuleDataSize">The size (in bytes) of the structure pointed to by pResolveModuleData.</param>
void ResolveModules(
[In] IntPtr pResolveModuleData,
[In] int resolveModuleDataSize);
/// <summary>
/// Called during GL_APPLICATION_STOP and signals managed
/// application end.
/// </summary>
/// <param name="reserved0">Do not use this parameter.</param>
/// <param name="reserved1">Do not use this parameter.</param>
/// <remarks>
/// It is acceptable for this method to unload the current AppDomain
/// and return COR_E_APPDOMAINUNLOADED.
/// </remarks>
void Stop(
[In] IntPtr reserved0,
[In] int reserved1);
}
}

View File

@@ -0,0 +1,25 @@
//------------------------------------------------------------------------------
// <copyright file="ICustomRuntimeManager.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System;
using System.Runtime.InteropServices;
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("A0BBBDFF-5AF5-42E3-9753-34441F764A6B")]
internal interface ICustomRuntimeManager {
// Registers an ICustomRuntime so that we can keep track of them.
[return: MarshalAs(UnmanagedType.Interface)]
ICustomRuntimeRegistrationToken Register(
[In, MarshalAs(UnmanagedType.Interface)] ICustomRuntime customRuntime);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("3A8E9CED-D3C9-4C4B-8956-6F15E2F559D9")]
internal interface ICustomRuntimeRegistrationToken {
// Unregisters an ICustomRuntime.
void Unregister();
}
}

View File

@@ -0,0 +1,36 @@
//------------------------------------------------------------------------------
// <copyright file="IIS7User.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Hosting {
using System;
using System.Text;
using System.Collections.Generic;
using System.Security.Principal;
internal sealed class IIS7UserPrincipal : IPrincipal {
// user object fields
private IIdentity _identity;
private IIS7WorkerRequest _wr;
internal IIS7UserPrincipal(IIS7WorkerRequest wr, IIdentity identity) {
_wr = wr;
_identity = identity;
}
//
// IPrincipal implementations
//
public IIdentity Identity {
get { return _identity; }
}
public bool IsInRole(String role) {
return _wr.IsUserInRole(role);
}
}
}

Some files were not shown because too many files have changed in this diff Show More