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 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
namespace System.Web.Mvc {
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Web;
using System.Web.Mvc.Async;
using System.Web.Mvc.Resources;
using System.Web.Routing;
using System.Web.SessionState;
using Microsoft.Web.Infrastructure.DynamicValidationHelper;
public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState {
private static readonly object _processRequestTag = new object();
private ControllerBuilder _controllerBuilder;
internal static readonly string MvcVersion = GetMvcVersionString();
public static readonly string MvcVersionHeaderName = "X-AspNetMvc-Version";
public MvcHandler(RequestContext requestContext) {
if (requestContext == null) {
throw new ArgumentNullException("requestContext");
}
RequestContext = requestContext;
}
internal ControllerBuilder ControllerBuilder {
get {
if (_controllerBuilder == null) {
_controllerBuilder = ControllerBuilder.Current;
}
return _controllerBuilder;
}
set {
_controllerBuilder = value;
}
}
public static bool DisableMvcResponseHeader {
get;
set;
}
protected virtual bool IsReusable {
get {
return false;
}
}
public RequestContext RequestContext {
get;
private set;
}
protected internal virtual void AddVersionHeader(HttpContextBase httpContext) {
if (!DisableMvcResponseHeader) {
httpContext.Response.AppendHeader(MvcVersionHeaderName, MvcVersion);
}
}
protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state) {
HttpContextBase iHttpContext = new HttpContextWrapper(httpContext);
return BeginProcessRequest(iHttpContext, callback, state);
}
protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) {
return SecurityUtil.ProcessInApplicationTrust(() => {
IController controller;
IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);
IAsyncController asyncController = controller as IAsyncController;
if (asyncController != null) {
// asynchronous controller
BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState) {
try {
return asyncController.BeginExecute(RequestContext, asyncCallback, asyncState);
}
catch {
factory.ReleaseController(asyncController);
throw;
}
};
EndInvokeDelegate endDelegate = delegate(IAsyncResult asyncResult) {
try {
asyncController.EndExecute(asyncResult);
}
finally {
factory.ReleaseController(asyncController);
}
};
SynchronizationContext syncContext = SynchronizationContextUtil.GetSynchronizationContext();
AsyncCallback newCallback = AsyncUtil.WrapCallbackForSynchronizedExecution(callback, syncContext);
return AsyncResultWrapper.Begin(newCallback, state, beginDelegate, endDelegate, _processRequestTag);
}
else {
// synchronous controller
Action action = delegate {
try {
controller.Execute(RequestContext);
}
finally {
factory.ReleaseController(controller);
}
};
return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag);
}
});
}
protected internal virtual void EndProcessRequest(IAsyncResult asyncResult) {
SecurityUtil.ProcessInApplicationTrust(() => {
AsyncResultWrapper.End(asyncResult, _processRequestTag);
});
}
private static string GetMvcVersionString() {
// DevDiv 216459:
// This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in
// medium trust. However, Assembly.FullName *is* accessible in medium trust.
return new AssemblyName(typeof(MvcHandler).Assembly.FullName).Version.ToString(2);
}
protected virtual void ProcessRequest(HttpContext httpContext) {
HttpContextBase iHttpContext = new HttpContextWrapper(httpContext);
ProcessRequest(iHttpContext);
}
protected internal virtual void ProcessRequest(HttpContextBase httpContext) {
SecurityUtil.ProcessInApplicationTrust(() => {
IController controller;
IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);
try {
controller.Execute(RequestContext);
}
finally {
factory.ReleaseController(controller);
}
});
}
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) {
// If request validation has already been enabled, make it lazy. This allows attributes like [HttpPost] (which looks
// at Request.Form) to work correctly without triggering full validation.
bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(HttpContext.Current);
if (isRequestValidationEnabled == true) {
ValidationUtility.EnableDynamicValidation(HttpContext.Current);
}
AddVersionHeader(httpContext);
RemoveOptionalRoutingParameters();
// Get the controller type
string controllerName = RequestContext.RouteData.GetRequiredString("controller");
// Instantiate the controller and call Execute
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);
if (controller == null) {
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentCulture,
MvcResources.ControllerBuilder_FactoryReturnedNull,
factory.GetType(),
controllerName));
}
}
private void RemoveOptionalRoutingParameters() {
RouteValueDictionary rvd = RequestContext.RouteData.Values;
// Get all keys for which the corresponding value is 'Optional'.
// ToArray() necessary so that we don't manipulate the dictionary while enumerating.
string[] matchingKeys = (from entry in rvd
where entry.Value == UrlParameter.Optional
select entry.Key).ToArray();
foreach (string key in matchingKeys) {
rvd.Remove(key);
}
}
#region IHttpHandler Members
bool IHttpHandler.IsReusable {
get {
return IsReusable;
}
}
void IHttpHandler.ProcessRequest(HttpContext httpContext) {
ProcessRequest(httpContext);
}
#endregion
#region IHttpAsyncHandler Members
IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
return BeginProcessRequest(context, cb, extraData);
}
void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) {
EndProcessRequest(result);
}
#endregion
}
}
|