From 58e0608c10c621b15fd9f396f8e46c567891b231 Mon Sep 17 00:00:00 2001 From: Matthias Bogad Date: Sun, 17 May 2015 19:54:05 +0200 Subject: [System.Web] ASP.Net MVC5 missing methods fixed I have added System.HttpApplication.RegisterModule(), the missing two properties of the System.Web.Routing.RouteCollection as well as the corresponding property in the HttpRuntimeSection to completely turn this off. Microsofts MIT-Licensed counterparts of the official System.Web assembly from github [0] were used as a reference. It is kind-of bolted on, but should be good enough until the whole open-sourced System.Web is incorporated. It should at least get the default MVC5 Template from Visual Studio 2013 up and running, once the async pipeline for the owin stuff is fixed. [0]: http://github.com/Microsoft/referencesource/ Additionally, the MissingMethodException "get_InClientBuildManager" in System.Web.Hosting.HostingEnvironment was fixed. In this commit, the following bugs were fixed: https://bugzilla.xamarin.com/show_bug.cgi?id=21810 https://bugzilla.xamarin.com/show_bug.cgi?id=16475 --- .../System.Web.Routing/RouteCollection.cs | 2 + .../HttpRuntimeSection.cs | 9 ++ .../System.Web.Hosting/HostingEnvironment.cs | 7 ++ .../System.Web/System.Web/DynamicModuleManager.cs | 57 +++++++++ mcs/class/System.Web/System.Web/HttpApplication.cs | 140 +++++++++++++++------ .../System.Web/net_4_5_System.Web.dll.sources | 1 + 6 files changed, 176 insertions(+), 40 deletions(-) create mode 100644 mcs/class/System.Web/System.Web/DynamicModuleManager.cs (limited to 'mcs/class') diff --git a/mcs/class/System.Web.Routing/System.Web.Routing/RouteCollection.cs b/mcs/class/System.Web.Routing/System.Web.Routing/RouteCollection.cs index b3e4a1c16dc..d53c063441e 100644 --- a/mcs/class/System.Web.Routing/System.Web.Routing/RouteCollection.cs +++ b/mcs/class/System.Web.Routing/System.Web.Routing/RouteCollection.cs @@ -92,6 +92,8 @@ namespace System.Web.Routing } } + public bool LowercaseUrls { get; set; } + public bool AppendTrailingSlash { get; set; } public bool RouteExistingFiles { get; set; } public void Add (string name, RouteBase item) diff --git a/mcs/class/System.Web/System.Web.Configuration_2.0/HttpRuntimeSection.cs b/mcs/class/System.Web/System.Web.Configuration_2.0/HttpRuntimeSection.cs index 62eb0716440..a328b5e18fc 100644 --- a/mcs/class/System.Web/System.Web.Configuration_2.0/HttpRuntimeSection.cs +++ b/mcs/class/System.Web/System.Web.Configuration_2.0/HttpRuntimeSection.cs @@ -63,6 +63,7 @@ namespace System.Web.Configuration static ConfigurationProperty encoderTypeProp; static ConfigurationProperty relaxedUrlToFileSystemMappingProp; static ConfigurationProperty targetFrameworkProp; + static ConfigurationProperty allowDynamicModuleRegistrationProp; static ConfigurationPropertyCollection properties; static HttpRuntimeSection () @@ -141,6 +142,8 @@ namespace System.Web.Configuration PropertyHelper.VersionConverter, PropertyHelper.DefaultValidator, ConfigurationPropertyOptions.None); + allowDynamicModuleRegistrationProp = new ConfigurationProperty ("allowDynamicModuleRegistration", typeof(bool), true, + ConfigurationPropertyOptions.None); properties = new ConfigurationPropertyCollection(); properties.Add (apartmentThreadingProp); @@ -169,6 +172,7 @@ namespace System.Web.Configuration properties.Add (encoderTypeProp); properties.Add (relaxedUrlToFileSystemMappingProp); properties.Add (targetFrameworkProp); + properties.Add (allowDynamicModuleRegistrationProp); } public HttpRuntimeSection() @@ -349,6 +353,11 @@ namespace System.Web.Configuration protected internal override ConfigurationPropertyCollection Properties { get { return properties; } } + [ConfigurationProperty ("allowDynamicModuleRegistration", DefaultValue = "True")] + public bool AllowDynamicModuleRegistration { + get { return (bool) base [allowDynamicModuleRegistrationProp]; } + set { base [allowDynamicModuleRegistrationProp] = value; } + } } } diff --git a/mcs/class/System.Web/System.Web.Hosting/HostingEnvironment.cs b/mcs/class/System.Web/System.Web.Hosting/HostingEnvironment.cs index ebf540bfb92..4b8a52f036d 100644 --- a/mcs/class/System.Web/System.Web.Hosting/HostingEnvironment.cs +++ b/mcs/class/System.Web/System.Web.Hosting/HostingEnvironment.cs @@ -104,6 +104,13 @@ namespace System.Web.Hosting { get { return vpath_provider; } } + public static bool InClientBuildManager { + get { + // Mono doesn't have a ClientBuildManager, so we can't be in it. Simple as that. + return false; + } + } + public static void DecrementBusyCount () { Interlocked.Decrement (ref busy_count); diff --git a/mcs/class/System.Web/System.Web/DynamicModuleManager.cs b/mcs/class/System.Web/System.Web/DynamicModuleManager.cs new file mode 100644 index 00000000000..99e0a36c653 --- /dev/null +++ b/mcs/class/System.Web/System.Web/DynamicModuleManager.cs @@ -0,0 +1,57 @@ +// +// DynamicModuleManager.cs: Manager for dynamic Http Modules. +// +// Author: +// Matthias Bogad (bogad@cs.tum.edu) +// +// (C) 2015 +// + +using System; +using System.Collections.Generic; + +namespace System.Web { + sealed class DynamicModuleManager { + const string moduleNameFormat = "__Module__{0}_{1}"; + + readonly List entries = new List (); + bool entriesAreReadOnly = false; + readonly object mutex = new object (); + + public void Add (Type moduleType) + { + if (moduleType == null) + throw new ArgumentException ("moduleType"); + + if (!typeof (IHttpModule).IsAssignableFrom (moduleType)) + throw new ArgumentException ("Given object does not implement IHttpModule.", "moduleType"); + + lock (mutex) { + if (entriesAreReadOnly) + throw new InvalidOperationException ("A module was to be added to the dynamic module list, but the list was already initialized. The dynamic module list can only be initialized once."); + + entries.Add (new DynamicModuleInfo (moduleType, + string.Format (moduleNameFormat, moduleType.AssemblyQualifiedName, Guid.NewGuid ()))); + } + } + + public ICollection LockAndGetModules () + { + lock (mutex) { + entriesAreReadOnly = true; + return entries; + } + } + } + + struct DynamicModuleInfo { + public readonly string Name; + public readonly Type Type; + + public DynamicModuleInfo (Type type, string name) + { + Name = name; + Type = type; + } + } +} diff --git a/mcs/class/System.Web/System.Web/HttpApplication.cs b/mcs/class/System.Web/System.Web/HttpApplication.cs index 68c098dcc26..34c2d105769 100644 --- a/mcs/class/System.Web/System.Web/HttpApplication.cs +++ b/mcs/class/System.Web/System.Web/HttpApplication.cs @@ -4,7 +4,8 @@ // Author: // Miguel de Icaza (miguel@novell.com) // Gonzalo Paniagua (gonzalo@ximian.com) -// +// Matthias Bogad (bogad@cs.tum.edu) +// // // Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com) // @@ -62,8 +63,10 @@ // Events Disposed // +using System; using System.IO; using System.Collections; +using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Diagnostics; @@ -162,6 +165,8 @@ namespace System.Web bool removeConfigurationFromCache; bool fullInitComplete = false; + static DynamicModuleManager dynamicModuleManeger = new DynamicModuleManager (); + // // These are used to detect the case where the EndXXX method is invoked // from within the BeginXXXX delegate, so we detect whether we kick the @@ -209,6 +214,13 @@ namespace System.Web if (context == null) context = HttpContext.Current; HttpModuleCollection coll = modules.LoadModules (this); + + HttpModuleCollection dynMods = CreateDynamicModules (); + + for (int i = 0; i < dynMods.Count; i++) { + coll.AddModule (dynMods.GetKey (i), dynMods.Get (i)); + } + Interlocked.CompareExchange (ref modcoll, coll, null); HttpContext.Current = saved; @@ -404,7 +416,7 @@ namespace System.Web public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); AcquireRequestState += new EventHandler (invoker.Invoke); } @@ -417,7 +429,7 @@ namespace System.Web public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); AuthenticateRequest += new EventHandler (invoker.Invoke); } @@ -430,7 +442,7 @@ namespace System.Web public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); AuthorizeRequest += new EventHandler (invoker.Invoke); } @@ -452,7 +464,7 @@ namespace System.Web public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); BeginRequest += new EventHandler (invoker.Invoke); } @@ -474,7 +486,7 @@ namespace System.Web public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); EndRequest += new EventHandler (invoker.Invoke); } @@ -487,7 +499,7 @@ namespace System.Web public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); PostRequestHandlerExecute += new EventHandler (invoker.Invoke); } @@ -500,7 +512,7 @@ namespace System.Web public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); PreRequestHandlerExecute += new EventHandler (invoker.Invoke); } @@ -513,7 +525,7 @@ namespace System.Web public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); ReleaseRequestState += new EventHandler (invoker.Invoke); } @@ -526,7 +538,7 @@ namespace System.Web public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); ResolveRequestCache += new EventHandler (invoker.Invoke); } @@ -539,7 +551,7 @@ namespace System.Web public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); UpdateRequestCache += new EventHandler (invoker.Invoke); } @@ -557,7 +569,7 @@ namespace System.Web public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); PostAuthenticateRequest += new EventHandler (invoker.Invoke); } @@ -575,7 +587,7 @@ namespace System.Web public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); PostAuthorizeRequest += new EventHandler (invoker.Invoke); } @@ -593,7 +605,7 @@ namespace System.Web public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); PostResolveRequestCache += new EventHandler (invoker.Invoke); } @@ -611,7 +623,7 @@ namespace System.Web public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); PostMapRequestHandler += new EventHandler (invoker.Invoke); } @@ -629,7 +641,7 @@ namespace System.Web public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); PostAcquireRequestState += new EventHandler (invoker.Invoke); } @@ -647,7 +659,7 @@ namespace System.Web public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); PostReleaseRequestState += new EventHandler (invoker.Invoke); } @@ -665,7 +677,7 @@ namespace System.Web public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); PostUpdateRequestCache += new EventHandler (invoker.Invoke); } @@ -674,61 +686,61 @@ namespace System.Web // public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); AcquireRequestState += new EventHandler (invoker.Invoke); } public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); AuthenticateRequest += new EventHandler (invoker.Invoke); } public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); AuthorizeRequest += new EventHandler (invoker.Invoke); } public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); BeginRequest += new EventHandler (invoker.Invoke); } public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); EndRequest += new EventHandler (invoker.Invoke); } public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); PostRequestHandlerExecute += new EventHandler (invoker.Invoke); } public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); PreRequestHandlerExecute += new EventHandler (invoker.Invoke); } public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); ReleaseRequestState += new EventHandler (invoker.Invoke); } public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); ResolveRequestCache += new EventHandler (invoker.Invoke); } public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data) { - AsyncInvoker invoker = new AsyncInvoker (bh, eh, data); + AsyncInvoker invoker = new AsyncInvoker (bh, eh, this, data); UpdateRequestCache += new EventHandler (invoker.Invoke); } @@ -749,7 +761,7 @@ namespace System.Web public void AddOnLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) { - AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state); + AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); LogRequest += new EventHandler (invoker.Invoke); } @@ -767,7 +779,7 @@ namespace System.Web public void AddOnMapRequestHandlerAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) { - AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state); + AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); MapRequestHandler += new EventHandler (invoker.Invoke); } @@ -785,7 +797,7 @@ namespace System.Web public void AddOnPostLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) { - AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state); + AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); PostLogRequest += new EventHandler (invoker.Invoke); } @@ -871,7 +883,7 @@ namespace System.Web // // If we catch an error, queue this error // - void ProcessError (Exception e) + internal void ProcessError (Exception e) { bool first = context.Error == null; context.AddError (e); @@ -1643,7 +1655,39 @@ namespace System.Web return true; } } - + + public static void RegisterModule (Type moduleType) + { + HttpRuntimeSection config = (HttpRuntimeSection)WebConfigurationManager.GetSection ("system.web/httpRuntime"); + + if (!config.AllowDynamicModuleRegistration) + throw new InvalidOperationException ("The Application has requested to register a dynamic Module, but dynamic module registration is disabled in web.config."); + + dynamicModuleManeger.Add (moduleType); + } + + + HttpModuleCollection CreateDynamicModules () + { + HttpModuleCollection modules = new HttpModuleCollection (); + + foreach (var module in dynamicModuleManeger.LockAndGetModules ()) { + IHttpModule httpModule = CreateModuleInstance (module.Type); + httpModule.Init (this); + modules.AddModule (module.Name, httpModule); + } + return modules; + } + + IHttpModule CreateModuleInstance (Type type) + { + return (IHttpModule) Activator.CreateInstance (type, + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance, + null, + null, + null); + } + #region internals internal void ClearError () { @@ -1891,24 +1935,40 @@ namespace System.Web public BeginEventHandler begin; public EndEventHandler end; public object data; + HttpApplication app; + AsyncCallback callback; - public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d) + public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, HttpApplication a, object d) { begin = bh; end = eh; data = d; + app = a; + callback = new AsyncCallback (doAsyncCallback); } - public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh) - { - begin = bh; - end = eh; - } + public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, HttpApplication app) : this(bh, eh, app, null) { } public void Invoke (object sender, EventArgs e) { - throw new Exception ("This is just a dummy"); + IAsyncResult res; + res = begin (app, e, callback, data); + } + + void doAsyncCallback (IAsyncResult res) + { + ThreadPool.QueueUserWorkItem ((object ores) => { + IAsyncResult tres = (IAsyncResult) ores; + try { + end (tres); + } catch (Exception ee) { + // I tried using ProcessError(), but we only come here frome an Invokation in PipelineDone(). + // Using ProcessError, I still get a blank screen, this way, we at least log the error to console... + Console.Error.WriteLine (ee.ToString ()); + } + }, res); } } #endregion } + diff --git a/mcs/class/System.Web/net_4_5_System.Web.dll.sources b/mcs/class/System.Web/net_4_5_System.Web.dll.sources index 8703eb00471..b074ec8f0a8 100644 --- a/mcs/class/System.Web/net_4_5_System.Web.dll.sources +++ b/mcs/class/System.Web/net_4_5_System.Web.dll.sources @@ -10,3 +10,4 @@ System.Web/UnvalidatedRequestValuesWrapper.cs System.Web/TaskAsyncResult.cs System.Web/TaskEventHandler.cs System.Web.Security/MembershipPasswordAttribute.cs +System.Web/DynamicModuleManager.cs -- cgit v1.2.3