1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Web.Caching;
using System.Web.Hosting;
using Microsoft.Web.Infrastructure;
namespace System.Web.WebPages
{
public abstract class ApplicationStartPage : WebPageExecutingBase
{
private static readonly Action<Action> _safeExecuteStartPageThunk = GetSafeExecuteStartPageThunk();
public static readonly string StartPageVirtualPath = "~/_appstart.";
public static readonly string CacheKeyPrefix = "__AppStartPage__";
public HttpApplication Application { get; internal set; }
public override HttpContextBase Context
{
get { return new HttpContextWrapper(Application.Context); }
}
public static HtmlString Markup { get; private set; }
internal static Exception Exception { get; private set; }
public TextWriter Output { get; internal set; }
public override string VirtualPath
{
get { return StartPageVirtualPath; }
set
{
// The virtual path for the start page is fixed for now.
throw new NotSupportedException();
}
}
internal void ExecuteInternal()
{
// See comments in GetSafeExecuteStartPageThunk().
_safeExecuteStartPageThunk(() =>
{
Output = new StringWriter(CultureInfo.InvariantCulture);
Execute();
Markup = new HtmlString(Output.ToString());
});
}
internal static void ExecuteStartPage(HttpApplication application)
{
ExecuteStartPage(application,
vpath => MonitorFile(vpath),
VirtualPathFactoryManager.Instance,
WebPageHttpHandler.GetRegisteredExtensions());
}
internal static void ExecuteStartPage(HttpApplication application, Action<string> monitorFile, IVirtualPathFactory virtualPathFactory, IEnumerable<string> supportedExtensions)
{
try
{
ExecuteStartPageInternal(application, monitorFile, virtualPathFactory, supportedExtensions);
}
catch (Exception e)
{
// Throw it as a HttpException so as to
// display the original stack trace information.
Exception = e;
throw new HttpException(null, e);
}
}
internal static void ExecuteStartPageInternal(HttpApplication application, Action<string> monitorFile, IVirtualPathFactory virtualPathFactory, IEnumerable<string> supportedExtensions)
{
ApplicationStartPage startPage = null;
foreach (var extension in supportedExtensions)
{
var vpath = StartPageVirtualPath + extension;
// We need to monitor regardless of existence because the user could add/remove the
// file at any time.
monitorFile(vpath);
if (!virtualPathFactory.Exists(vpath))
{
continue;
}
if (startPage == null)
{
startPage = virtualPathFactory.CreateInstance<ApplicationStartPage>(vpath);
startPage.Application = application;
startPage.VirtualPathFactory = virtualPathFactory;
startPage.ExecuteInternal();
}
}
}
private static Action<Action> GetSafeExecuteStartPageThunk()
{
// Programmatically detect if this version of System.Web.dll suffers from a bug in
// which HttpUtility.HtmlEncode can't be called from Application_Start, and if so
// set the current HttpContext to null to work around it.
//
// See Dev10 #906296 and Dev10 #898600 for more information.
if (typeof(HttpResponse).GetProperty("DisableCustomHttpEncoder", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) != null)
{
// this version suffers from the bug
return HttpContextHelper.ExecuteInNullContext;
}
else
{
// this version does not suffer from the bug
return action => action();
}
}
private static void InitiateShutdown(string key, object value, CacheItemRemovedReason reason)
{
// Only handle case when the dependency has changed.
if (reason != CacheItemRemovedReason.DependencyChanged)
{
return;
}
ThreadPool.QueueUserWorkItem(new WaitCallback(ShutdownCallBack));
}
private static void MonitorFile(string virtualPath)
{
var virtualPathDependencies = new List<string>();
virtualPathDependencies.Add(virtualPath);
CacheDependency cacheDependency = HostingEnvironment.VirtualPathProvider.GetCacheDependency(
virtualPath, virtualPathDependencies, DateTime.UtcNow);
var key = CacheKeyPrefix + virtualPath;
HttpRuntime.Cache.Insert(key, virtualPath, cacheDependency,
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
CacheItemPriority.NotRemovable, new CacheItemRemovedCallback(InitiateShutdown));
}
private static void ShutdownCallBack(object state)
{
InfrastructureHelper.UnloadAppDomain();
}
public override void Write(HelperResult result)
{
if (result != null)
{
result.WriteTo(Output);
}
}
public override void WriteLiteral(object value)
{
Output.Write(value);
}
public override void Write(object value)
{
Output.Write(HttpUtility.HtmlEncode(value));
}
protected internal override TextWriter GetOutputWriter()
{
return Output;
}
}
}
|