Ver Fonte

2009-06-27 Marek Habersack <[email protected]>

    	* MetaModel.cs: implemented DynamicDataFolderVirtualPath

    	* DynamicDataRouteHandler.cs: implemented SetRequestMetaTable,
    	GetCustomPageVirtualPath, GetScaffoldPageVirtualPath and
    	guessed at implementation of CreateHandler.

    2009-06-27  Marek Habersack  <[email protected]>

    	* MetaModelTest.cs: added test for DynamicDataFolderVirtualPath

    	* DynamicDataRouteHandlerTest.cs: implemented tests for
    	CreateHandler (one of them isn't working atm),
    	GetCustomVirtualPagePath, GetScaffoldVirtualPagePath,
    	GetRequestMetaTable, SetRequestMetaTable

    2009-06-26  Marek Habersack  <[email protected]>

    	* DynamicDataRouteTest.cs: MyDataContext3 is safely registered in
    	the fixture setup method.
    	Enabled the GetTableFromRouteData3 and GetRouteData tests - the
    	work fine now.
    	Added test for the RouteHandler property.

    	* DynamicDataRouteHandlerTest.cs: added tests for the constructor
    	and the Model property.

    2009-06-26  Marek Habersack  <[email protected]>

    	* MetaModel.cs: RegisterContextCore preserves already registered
    	tables.

    	* DynamicDataRouteHandler.cs: GetRequestContext must not retrieve
    	route data from the routes collection (if the matching route
    	happened to be an instance of DynamicDataRoute it would initialize
    	its RouteHandler's Model property, which is not correct, according
    	to tests). Instead a new RouteData instance is created each time
    	we don't find any cached context.

    	* DynamicDataRoute.cs: the associated route handler is set its
    	Model property when we initialize for the first time.
    	GetRouteData checks whether route data returned by base class
    	relates to a table which exists in the current context. If no such
    	table exists, null is returned.

svn path=/trunk/mcs/; revision=137013
Marek Habersack há 16 anos atrás
pai
commit
3192ec7fa4

+ 26 - 0
mcs/class/System.Web.DynamicData/System.Web.DynamicData/ChangeLog

@@ -1,3 +1,29 @@
+2009-06-27  Marek Habersack  <[email protected]>
+
+	* MetaModel.cs: implemented DynamicDataFolderVirtualPath
+
+	* DynamicDataRouteHandler.cs: implemented SetRequestMetaTable,
+	GetCustomPageVirtualPath, GetScaffoldPageVirtualPath and
+	guessed at implementation of CreateHandler.
+
+2009-06-26  Marek Habersack  <[email protected]>
+
+	* MetaModel.cs: RegisterContextCore preserves already registered
+	tables.
+
+	* DynamicDataRouteHandler.cs: GetRequestContext must not retrieve
+	route data from the routes collection (if the matching route
+	happened to be an instance of DynamicDataRoute it would initialize
+	its RouteHandler's Model property, which is not correct, according
+	to tests). Instead a new RouteData instance is created each time
+	we don't find any cached context.
+
+	* DynamicDataRoute.cs: the associated route handler is set its
+	Model property when we initialize for the first time.
+	GetRouteData checks whether route data returned by base class
+	relates to a table which exists in the current context. If no such
+	table exists, null is returned.
+
 2009-06-25  Marek Habersack  <[email protected]>
 
 	* MetaTable.cs: Fixes to make tests succeed.

+ 16 - 2
mcs/class/System.Web.DynamicData/System.Web.DynamicData/DynamicDataRoute.cs

@@ -59,7 +59,7 @@ namespace System.Web.DynamicData
 		public MetaModel Model { get; set; }
 
 		public DynamicDataRouteHandler RouteHandler { 
-			get { return (DynamicDataRouteHandler) base.RouteHandler; }
+			get { return base.RouteHandler as DynamicDataRouteHandler; }
 			set { base.RouteHandler = value; }
 		}
 
@@ -79,6 +79,10 @@ namespace System.Web.DynamicData
 					return;
 				
 				initDone = true;
+
+				DynamicDataRouteHandler rh = RouteHandler;
+				if (rh != null)
+					rh.Model = Model;
 				
 				string action = Action, table = Table;
 				if (action == null && table == null)
@@ -119,7 +123,17 @@ namespace System.Web.DynamicData
 		public override RouteData GetRouteData (HttpContextBase httpContext)
 		{
 			EnsureInitialized ();
-			return base.GetRouteData (httpContext);
+			RouteData rd = base.GetRouteData (httpContext);
+
+			if (rd == null)
+				return null;
+
+			MetaModel model = Model ?? MetaModel.Default;
+			MetaTable table;
+			if (model == null || !model.TryGetTable (rd.GetRequiredString ("Table"), out table))
+				return null;
+			
+			return rd;
 		}
 
 		public MetaTable GetTableFromRouteData (RouteData routeData)

+ 64 - 24
mcs/class/System.Web.DynamicData/System.Web.DynamicData/DynamicDataRouteHandler.cs

@@ -39,6 +39,7 @@ using System.Security.Principal;
 using System.Threading;
 using System.Web.Caching;
 using System.Web.Compilation;
+using System.Web.Hosting;
 using System.Web.Routing;
 using System.Web.UI;
 
@@ -62,41 +63,40 @@ namespace System.Web.DynamicData
 			}
 		}
 
-		public static RequestContext GetRequestContext (HttpContext httpContext)
+		static RouteContext GetOrCreateRouteContext (HttpContext httpContext)
 		{
-			if (httpContext == null)
-				throw new ArgumentNullException ("httpContext");
-			
-			RouteContext rc;
+			RouteContext rc = null;
 			bool locked = false;
 			try {
 				contextsLock.EnterReadLock ();
 				locked = true;
 				if (contexts.TryGetValue (httpContext, out rc) && rc != null)
-					return rc.Context;
+					return rc;
 			} finally {
 				if (locked)
 					contextsLock.ExitReadLock ();
 			}
 
-			var ctxWrapper = new HttpContextWrapper (httpContext);
-			RouteData rd = RouteTable.Routes.GetRouteData (ctxWrapper);
-			if (rd == null)
-				rd = new RouteData ();
-			
-			var ret = new RequestContext (ctxWrapper, rd);
-
 			locked = false;
 			try {
 				contextsLock.EnterWriteLock ();
 				locked = true;
-				contexts.Add (httpContext, MakeRouteContext (ret, null, null, null));
+				rc = MakeRouteContext (new RequestContext (new HttpContextWrapper (httpContext), new RouteData ()), null, null, null);
+				contexts.Add (httpContext, rc);
 			} finally {
 				if (locked)
 					contextsLock.ExitWriteLock ();
 			}
 
-			return ret;
+			return rc;
+		}
+		
+		public static RequestContext GetRequestContext (HttpContext httpContext)
+		{
+			if (httpContext == null)
+				throw new ArgumentNullException ("httpContext");
+			
+			return GetOrCreateRouteContext (httpContext).Context;
 		}
 
 		public static MetaTable GetRequestMetaTable (HttpContext httpContext)
@@ -119,10 +119,13 @@ namespace System.Web.DynamicData
 			return null;
 		}
 
-		[MonoTODO]
 		public static void SetRequestMetaTable (HttpContext httpContext, MetaTable table)
 		{
-			throw new NotImplementedException ();
+			// And tradiationally... some .NET emulation code
+			if (httpContext == null)
+				throw new NullReferenceException ();
+
+			GetOrCreateRouteContext (httpContext).Table = table;
 		}
 
 		public DynamicDataRouteHandler ()
@@ -131,23 +134,60 @@ namespace System.Web.DynamicData
 
 		public MetaModel Model { get; internal set; }
 
-		[MonoTODO]
+		[MonoTODO ("Needs a working test")]
 		public virtual IHttpHandler CreateHandler (DynamicDataRoute route, MetaTable table, string action)
 		{
-			var vp = String.Concat (String.Concat (HttpContext.Current.Request.ApplicationPath, "DynamicData/PageTemplates/", action, ".aspx"));
-			return (IHttpHandler) BuildManager.CreateInstanceFromVirtualPath (vp, typeof (Page));
+			// .NET bug emulation mode
+			if (route == null || table == null || action == null)
+				throw new NullReferenceException ();
+
+			// NOTE: all code below is a result of guessing as no tests succeed for this
+			// call so far!
+
+			IHttpHandler ret = null;
+			
+			// Give custom pages a chance
+			string viewName = String.IsNullOrEmpty (action) ? route.ViewName : action;
+			string path = GetCustomPageVirtualPath (table, viewName);
+
+			// Pages might be in app resources, need to use a VPP
+			VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
+			
+			if (vpp != null && vpp.FileExists (path))
+				ret = BuildManager.CreateInstanceFromVirtualPath (path, typeof (Page)) as IHttpHandler;
+
+			if (ret != null)
+				return ret;
+
+			path = GetScaffoldPageVirtualPath (table, viewName);
+			if (vpp != null && vpp.FileExists (path))
+				ret = BuildManager.CreateInstanceFromVirtualPath (path, typeof (Page)) as IHttpHandler;
+			
+			return ret;
 		}
 
-		[MonoTODO]
 		protected virtual string GetCustomPageVirtualPath (MetaTable table, string viewName)
 		{
-			throw new NotImplementedException ();
+			// No such checks are made in .NET, we won't follow the pattern...
+			MetaModel model = Model;
+			if (table == null || model == null)
+				throw new NullReferenceException (); // yuck
+
+			// Believe it or not, this is what .NET does - pass a null/empty viewName
+			// and you get /.aspx at the end...
+			return model.DynamicDataFolderVirtualPath + "CustomPages/" + table.Name + "/" + viewName + ".aspx";
 		}
 
-		[MonoTODO]
 		protected virtual string GetScaffoldPageVirtualPath (MetaTable table, string viewName)
 		{
-			throw new NotImplementedException ();
+			// No such checks are made in .NET, we won't follow the pattern...
+			MetaModel model = Model;
+			if (table == null || model == null)
+				throw new NullReferenceException (); // yuck
+
+			// Believe it or not, this is what .NET does - pass a null/empty viewName
+			// and you get /.aspx at the end...
+			return model.DynamicDataFolderVirtualPath + "PageTemplates/" + viewName + ".aspx";
 		}
 
 		IHttpHandler IRouteHandler.GetHttpHandler (RequestContext requestContext)

+ 19 - 3
mcs/class/System.Web.DynamicData/System.Web.DynamicData/MetaModel.cs

@@ -46,6 +46,8 @@ namespace System.Web.DynamicData
 	[AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
 	public class MetaModel
 	{
+		const string DEFAULT_DYNAMIC_DATA_VIRTUAL_FOLDER_PATH = "~/DynamicData/";
+		
 		static object registered_models_lock = new object ();
 		
 		static MetaModel default_model;
@@ -53,6 +55,7 @@ namespace System.Web.DynamicData
 		static Dictionary<Type, MetaModel> registered_models;
 
 		DataModelProvider provider;
+		string dynamicDataFolderVirtualPath;
 		
 		public static MetaModel Default {
 			get { return default_model; }
@@ -81,13 +84,26 @@ namespace System.Web.DynamicData
 			if (default_model == null)
 				default_model = this;
 
-			DynamicDataFolderVirtualPath = "~/DynamicData/";
 			FieldTemplateFactory = new FieldTemplateFactory ();
 			Tables = new ReadOnlyCollection<MetaTable> (new MetaTable [0]);
 			VisibleTables = new List<MetaTable> ();
 		}
 
-		public string DynamicDataFolderVirtualPath { get; set; }
+		public string DynamicDataFolderVirtualPath {
+			get {
+				if (dynamicDataFolderVirtualPath == null)
+					return DEFAULT_DYNAMIC_DATA_VIRTUAL_FOLDER_PATH;
+
+				return dynamicDataFolderVirtualPath;
+			}
+			
+			set {
+				if (!String.IsNullOrEmpty (value))
+					dynamicDataFolderVirtualPath = VirtualPathUtility.AppendTrailingSlash (value);
+				else
+					dynamicDataFolderVirtualPath = value;
+			}
+		}
 
 		public IFieldTemplateFactory FieldTemplateFactory { get; set; }
 
@@ -211,7 +227,7 @@ namespace System.Web.DynamicData
 
 		void RegisterContextCore (DataModelProvider dataModelProvider, ContextConfiguration configuration)
 		{
-			var l = new List<MetaTable> ();
+			var l = new List<MetaTable> (Tables);
 			foreach (var t in dataModelProvider.Tables)
 				l.Add (new MetaTable (this, t, configuration));
 			

+ 3 - 0
mcs/class/System.Web.DynamicData/System.Web.DynamicData_test.dll.sources

@@ -62,6 +62,9 @@ Common/FooWithToString.cs
 Common/ITestDataContext.cs
 Common/KnownResponseHeader.cs
 Common/Mocks.cs
+Common/MyDynamicDataRouteHandler.cs
+Common/MyHttpContextWrapper.cs
+Common/MyHttpRequestWrapper.cs
 Common/TestDataColumn.cs
 Common/TestDataContainer.cs
 Common/TestDataContext2.cs

+ 28 - 0
mcs/class/System.Web.DynamicData/Test/Common/MyDynamicDataRouteHandler.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Web;
+using System.Web.UI;
+using System.Web.DynamicData;
+
+namespace MonoTests.Common
+{
+	class MyDynamicDataRouteHandler : DynamicDataRouteHandler
+	{
+		public string DoGetCustomPageVirtualPath (MetaTable table, string viewName)
+		{
+			return GetCustomPageVirtualPath (table, viewName);
+		}
+		
+		public string DoGetScaffoldPageVirtualPath (MetaTable table, string viewName)
+		{
+			return GetScaffoldPageVirtualPath (table, viewName);
+		}
+
+		public override IHttpHandler CreateHandler (DynamicDataRoute route, MetaTable table, string action)
+		{
+			return new Page () as IHttpHandler;
+		}
+	}
+}

+ 22 - 0
mcs/class/System.Web.DynamicData/Test/Common/MyHttpContextWrapper.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Web;
+
+namespace MonoTests.Common
+{
+	class MyHttpContextWrapper : HttpContextBase
+	{
+		MyHttpRequestWrapper request;
+
+		public override HttpRequestBase Request {
+			get {
+				if (request == null)
+					request = new MyHttpRequestWrapper ();
+
+				return request;
+			}
+		}
+	}
+}

+ 83 - 0
mcs/class/System.Web.DynamicData/Test/Common/MyHttpRequestWrapper.cs

@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Web;
+
+namespace MonoTests.Common
+{
+	class MyHttpRequestWrapper : HttpRequestBase
+	{
+		Dictionary<string, object> propertyValues = new Dictionary<string, object> ();
+
+		public override string AppRelativeCurrentExecutionFilePath
+		{
+			get
+			{
+				string value;
+				if (!GetProperty<string> ("AppRelativeCurrentExecutionFilePath", out value))
+					return base.AppRelativeCurrentExecutionFilePath;
+
+				return value;
+			}
+		}
+
+		public override string PathInfo
+		{
+			get
+			{
+				string value;
+				if (!GetProperty<string> ("PathInfo", out value))
+					return base.PathInfo;
+
+				return value;
+			}
+		}
+
+		public override NameValueCollection QueryString
+		{
+			get
+			{
+				NameValueCollection value;
+				if (!GetProperty<NameValueCollection> ("QueryString", out value))
+					return base.QueryString;
+
+				return value;
+			}
+		}
+
+		bool GetProperty<T> (string name, out T value)
+		{
+			if (String.IsNullOrEmpty (name))
+				throw new ArgumentNullException ("name");
+
+			value = default (T);
+			object v;
+			if (propertyValues.TryGetValue (name, out v)) {
+				if (v == null)
+					return true;
+				if (typeof (T).IsAssignableFrom (v.GetType ())) {
+					value = (T) v;
+					return true;
+				}
+
+				throw new InvalidOperationException ("Invalid value type. Expected '" + typeof (T) + "' and got '" + v.GetType () + "'");
+			}
+
+			return false;
+		}
+
+		public void SetProperty (string name, object value)
+		{
+			if (String.IsNullOrEmpty (name))
+				return;
+
+			if (propertyValues.ContainsKey (name))
+				propertyValues[name] = value;
+			else
+				propertyValues.Add (name, value);
+		}
+	}
+}

+ 0 - 8
mcs/class/System.Web.DynamicData/Test/Common/TestStubTypes.cs

@@ -77,14 +77,6 @@ namespace MonoTests.System.Web.DynamicData
         }
     }
 
-	class MyDynamicDataRouteHandler : DynamicDataRouteHandler
-	{
-		public override IHttpHandler CreateHandler (DynamicDataRoute route, MetaTable table, string action)
-		{
-			return new Page () as IHttpHandler;
-		}
-	}
-
 	class MyDataContext1 : DataContext
 	{
 		public MyDataContext1 ()

+ 44 - 0
mcs/class/System.Web.DynamicData/Test/Common/Utils.cs

@@ -70,11 +70,21 @@ namespace MonoTests.Common
 			RegisterContext (model, null);
 		}
 
+		public static void RegisterContext (Type contextType)
+		{
+			RegisterContext (contextType, null);
+		}
+
 		public static void RegisterContext (DataModelProvider model, ContextConfiguration config)
 		{
 			RegisterContext (model, config, true);
 		}
 
+		public static void RegisterContext (Type contextType, ContextConfiguration config)
+		{
+			RegisterContext (contextType, config, true);
+		}
+		
 		public static void RegisterContext (DataModelProvider model, ContextConfiguration config, bool defaultModel)
 		{
 			// Just in case no model has been created yet
@@ -105,6 +115,40 @@ namespace MonoTests.Common
 			}
 		}
 
+		public static void RegisterContext (Type contextType, ContextConfiguration config, bool defaultModel)
+		{
+			// Just in case no model has been created yet
+			MetaModel m = new MetaModel ();
+
+			if (defaultModel)
+				m = MetaModel.Default;
+
+			Exception exception = null;
+			MetaModel registered = null;
+
+			try {
+				registered = MetaModel.GetModel (contextType);
+			} catch (Exception) {
+				// ignore
+			}
+
+			try {
+				if (registered == null) {
+					if (config != null)
+						m.RegisterContext (contextType, config);
+					else
+						m.RegisterContext (contextType);
+				}
+			} catch (InvalidOperationException ex) {
+				exception = ex;
+			}
+
+			if (exception != null) {
+				Console.WriteLine ("RegisterContext exception:");
+				Console.WriteLine (exception);
+			}
+		}
+
 		public static string BuildActionName (MetaTable table, string action)
 		{
 			return "/" + table.Name + "/" + action + ".aspx";

+ 20 - 0
mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/ChangeLog

@@ -1,3 +1,23 @@
+2009-06-27  Marek Habersack  <[email protected]>
+
+	* MetaModelTest.cs: added test for DynamicDataFolderVirtualPath
+
+	* DynamicDataRouteHandlerTest.cs: implemented tests for
+	CreateHandler (one of them isn't working atm),
+	GetCustomVirtualPagePath, GetScaffoldVirtualPagePath,
+	GetRequestMetaTable, SetRequestMetaTable
+
+2009-06-26  Marek Habersack  <[email protected]>
+
+	* DynamicDataRouteTest.cs: MyDataContext3 is safely registered in
+	the fixture setup method.
+	Enabled the GetTableFromRouteData3 and GetRouteData tests - the
+	work fine now.
+	Added test for the RouteHandler property.
+
+	* DynamicDataRouteHandlerTest.cs: added tests for the constructor
+	and the Model property.
+
 2009-06-25  Marek Habersack  <[email protected]>
 
 	* MetaTableTest.cs: new GetVirtualPath tests.

+ 276 - 0
mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicDataRouteHandlerTest.cs

@@ -61,6 +61,136 @@ namespace MonoTests.System.Web.DynamicData
 	[TestFixture]
 	public class DynamicDataRouteHandlerTest
 	{
+		DynamicDataContainerModelProvider dynamicModelProvider;
+
+		[TestFixtureSetUp]
+		public void SetUp ()
+		{
+			dynamicModelProvider = new DynamicDataContainerModelProvider (typeof (TestDataContainer<TestDataContext>));
+			Utils.RegisterContext (dynamicModelProvider, new ContextConfiguration () { ScaffoldAllTables = true });
+		}
+
+		[Test]
+		public void Constructor ()
+		{
+			var ddrh = new DynamicDataRouteHandler ();
+
+			Assert.AreEqual (null, ddrh.Model, "#A1");
+		}
+
+		[Test]
+		public void CreateHandlerParams ()
+		{
+			MetaModel m = Utils.CommonInitialize ();
+
+			var route = RouteTable.Routes[0] as DynamicDataRoute;
+			MetaTable t = m.Tables[TestDataContext.TableFooEmpty];
+			var handler = route.RouteHandler = new DynamicDataRouteHandler ();
+
+			// No null check is made, of course - throws from some internal method
+			AssertExtensions.Throws<NullReferenceException> (() => {
+				handler.CreateHandler (null, t, PageAction.Details);
+			}, "#A1");
+
+			// No null check again - this time throws from GetCustomPageVirtualPath
+			AssertExtensions.Throws<NullReferenceException> (() => {
+				handler.CreateHandler (route, null, PageAction.Details);
+			}, "#A2");
+
+			// And once again, no null check and thrown from GetCustomPageVirtualPath as well
+			AssertExtensions.Throws<NullReferenceException> (() => {
+				handler.CreateHandler (route, t, null);
+			}, "#A3");
+		}
+
+		[Test]
+		[Ignore ("Throws NREX on .NET - no idea why and how to make it work. Probably needs full request emulation (using Mainsoft test suite)")]
+		// Probably need to simulate a full reqest using similar environment as System.Web tests
+		public void CreateHandler ()
+		{
+			MetaModel m = Utils.CommonInitialize ();
+
+			var route = RouteTable.Routes[0] as DynamicDataRoute;
+			MetaTable t = m.Tables[TestDataContext.TableFooEmpty];
+			Assert.IsNotNull (t, "#A1");
+
+			var handler = route.RouteHandler = new DynamicDataRouteHandler ();
+			var wrapper = new MyHttpContextWrapper ();
+			var request = wrapper.Request as MyHttpRequestWrapper;
+			request.SetProperty ("AppRelativeCurrentExecutionFilePath", "~/FooEmptyTable/List.aspx");
+			request.SetProperty ("PathInfo", String.Empty);
+
+			// This must be non-null because DynamicData doesn't care to check whether the returned
+			// value is null or not...
+			request.SetProperty ("QueryString", new NameValueCollection ());
+
+			// This will assign the route handler's Model property
+			RouteData rd = route.GetRouteData (wrapper);
+			Assert.IsNotNull (handler.Model, "#A2");
+
+			// Throws a NREX from some internal method - no slightest idea why, as none of the parameters
+			// passed are null
+			IHttpHandler h = handler.CreateHandler (route, t, PageAction.Details);
+			Assert.IsNotNull (h, "#A3");
+			Assert.AreEqual (typeof (Page), h.GetType (), "#A3-1");
+
+			var page = h as Page;
+			Assert.AreEqual (String.Empty, page.AppRelativeVirtualPath, "#A3-2");
+		}
+
+		[Test]
+		public void GetCustomPageVirtualPath ()
+		{
+			MetaModel m = Utils.CommonInitialize ();
+			var route = RouteTable.Routes[0] as DynamicDataRoute;
+
+			MetaTable t = m.Tables[TestDataContext.TableFooEmpty];
+			Assert.IsNotNull (t, "#A1");
+
+			// We neeed the handler to have its Model property set
+			route.RouteHandler = new MyDynamicDataRouteHandler ();
+			var handler = route.RouteHandler as MyDynamicDataRouteHandler;
+			Assert.IsNotNull (handler, "#A2");
+
+			// Lack of null check (for table)
+			AssertExtensions.Throws<NullReferenceException> (() => {
+				handler.DoGetCustomPageVirtualPath (null, null);
+			}, "#A2-1");
+
+			// Another missing null check (this time for Model)... Are null checks
+			// out of fashion?
+			AssertExtensions.Throws<NullReferenceException> (() => {
+				handler.DoGetCustomPageVirtualPath (t, String.Empty);
+			}, "#A2-2");
+
+			var wrapper = new MyHttpContextWrapper ();
+			var request = wrapper.Request as MyHttpRequestWrapper;
+			request.SetProperty ("AppRelativeCurrentExecutionFilePath", "~/FooEmptyTable/List.aspx");
+			request.SetProperty ("PathInfo", String.Empty);
+
+			// This must be non-null because DynamicData doesn't care to check whether the returned
+			// value is null or not...
+			request.SetProperty ("QueryString", new NameValueCollection ());
+
+			// This will assign the route handler's Model property
+			RouteData rd = route.GetRouteData (wrapper);
+			Assert.IsNotNull (handler.Model, "#A3");
+
+			Assert.AreEqual (handler.Model.DynamicDataFolderVirtualPath + "CustomPages/" + t.Name + "/MyCustomPage.aspx", 
+				handler.DoGetCustomPageVirtualPath (t, "MyCustomPage"), "#A4");
+
+			handler.Model.DynamicDataFolderVirtualPath = "~/MyFolder";
+			Assert.AreEqual (handler.Model.DynamicDataFolderVirtualPath + "CustomPages/" + t.Name + "/MyCustomPage.aspx",
+				handler.DoGetCustomPageVirtualPath (t, "MyCustomPage"), "#A5");
+
+			// doh!
+			Assert.AreEqual (handler.Model.DynamicDataFolderVirtualPath + "CustomPages/" + t.Name + "/.aspx",
+				handler.DoGetCustomPageVirtualPath (t, null), "#A6");
+
+			Assert.AreEqual (handler.Model.DynamicDataFolderVirtualPath + "CustomPages/" + t.Name + "/.aspx",
+				handler.DoGetCustomPageVirtualPath (t, String.Empty), "#A7");
+		}
+
 		[Test]
 		public void GetRequestContext ()
 		{
@@ -81,5 +211,151 @@ namespace MonoTests.System.Web.DynamicData
 			Assert.IsNotNull (rc.RouteData.Values, "#C1-2");
 			Assert.AreEqual (0, rc.RouteData.Values.Count, "#C1-3");
 		}
+
+		[Test]
+		public void GetRequestMetaTable ()
+		{
+			MetaModel m = Utils.CommonInitialize ();
+			var route = RouteTable.Routes[0] as DynamicDataRoute;
+			MetaTable t = m.Tables[TestDataContext.TableFooDisplayName];
+			Assert.IsNotNull (t, "#A1");
+
+			// Surprise! A null check is present!
+			AssertExtensions.Throws<ArgumentNullException> (() => {
+				DynamicDataRouteHandler.GetRequestMetaTable (null);
+			}, "#A2");
+			
+			MetaTable t2 = DynamicDataRouteHandler.GetRequestMetaTable (HttpContext.Current);
+			Assert.IsNull (t2, "#A3");
+
+			DynamicDataRouteHandler.SetRequestMetaTable (HttpContext.Current, t);
+			t2 = DynamicDataRouteHandler.GetRequestMetaTable (HttpContext.Current);
+			Assert.IsNotNull (t2, "#A4");
+			Assert.AreEqual (t, t2, "#A4-1");
+		}
+
+		[Test]
+		public void GetScaffoldPageVirtualPath ()
+		{
+			MetaModel m = Utils.CommonInitialize ();
+			var route = RouteTable.Routes[0] as DynamicDataRoute;
+
+			MetaTable t = m.Tables[TestDataContext.TableFooDisplayName];
+			Assert.IsNotNull (t, "#A1");
+
+			// We neeed the handler to have its Model property set
+			route.RouteHandler = new MyDynamicDataRouteHandler ();
+			var handler = route.RouteHandler as MyDynamicDataRouteHandler;
+			Assert.IsNotNull (handler, "#A2");
+
+			// Lack of null check (for table)
+			AssertExtensions.Throws<NullReferenceException> (() => {
+				handler.DoGetScaffoldPageVirtualPath (null, null);
+			}, "#A2-1");
+
+			// Another missing null check (this time for Model)... Are null checks
+			// out of fashion?
+			AssertExtensions.Throws<NullReferenceException> (() => {
+				handler.DoGetScaffoldPageVirtualPath (t, String.Empty);
+			}, "#A2-2");
+
+			var wrapper = new MyHttpContextWrapper ();
+			var request = wrapper.Request as MyHttpRequestWrapper;
+			request.SetProperty ("AppRelativeCurrentExecutionFilePath", "~/FooDisplayNameTable/List.aspx");
+			request.SetProperty ("PathInfo", String.Empty);
+
+			// This must be non-null because DynamicData doesn't care to check whether the returned
+			// value is null or not...
+			request.SetProperty ("QueryString", new NameValueCollection ());
+
+			// This will assign the route handler's Model property
+			RouteData rd = route.GetRouteData (wrapper);
+			Assert.IsNotNull (handler.Model, "#A3");
+
+			Assert.AreEqual (handler.Model.DynamicDataFolderVirtualPath + "PageTemplates/" + "MyCustomPage.aspx",
+				handler.DoGetScaffoldPageVirtualPath (t, "MyCustomPage"), "#A4");
+
+			handler.Model.DynamicDataFolderVirtualPath = "~/MyFolder";
+			Assert.AreEqual (handler.Model.DynamicDataFolderVirtualPath + "PageTemplates/" + "MyCustomPage.aspx",
+				handler.DoGetScaffoldPageVirtualPath (t, "MyCustomPage"), "#A5");
+
+			// doh!
+			Assert.AreEqual (handler.Model.DynamicDataFolderVirtualPath + "PageTemplates/" + ".aspx",
+				handler.DoGetScaffoldPageVirtualPath (t, null), "#A6");
+
+			Assert.AreEqual (handler.Model.DynamicDataFolderVirtualPath + "PageTemplates/" + ".aspx",
+				handler.DoGetScaffoldPageVirtualPath (t, String.Empty), "#A7");
+		}
+
+		[Test]
+		public void Model ()
+		{
+			MetaModel m = Utils.CommonInitialize ();
+			var route = RouteTable.Routes[0] as DynamicDataRoute;
+
+			Assert.IsNotNull (route, "#A1");
+			Assert.IsNotNull (route.Model, "#A1-1");
+			var handler = route.RouteHandler;
+
+			Assert.IsNotNull (handler, "#A2");
+			Assert.IsTrue (handler.GetType () == typeof (MyDynamicDataRouteHandler), "#A2-1");
+			Assert.IsNull (handler.Model, "#A2-2");
+
+			var req = new FakeHttpWorkerRequest ();
+			var ctx = new HttpContext (req);
+
+			RequestContext rc = DynamicDataRouteHandler.GetRequestContext (ctx);
+			Assert.IsNotNull (rc, "#B1");
+			Assert.IsNull (handler.Model, "#B1-2");
+
+			var wrapper = new MyHttpContextWrapper ();
+			var request = wrapper.Request as MyHttpRequestWrapper;
+
+			// It appears .NET checks whether the indicated table exists - if not, GetRouteData will return
+			// null (even though the Route class will find a match)
+			request.SetProperty ("AppRelativeCurrentExecutionFilePath", "~/NoSuchTable/List.aspx");
+			request.SetProperty ("PathInfo", String.Empty);
+
+			// This must be non-null because DynamicData doesn't care to check whether the returned
+			// value is null or not...
+			request.SetProperty ("QueryString", new NameValueCollection ());
+			
+			// No table FooTable in the context - returns null
+			RouteData rd = route.GetRouteData (wrapper);
+			Assert.IsNull (rd, "#C1");
+
+			// Apparently Model is set in the above call even though it returns null
+			Assert.IsNotNull (handler.Model, "#C1-1");
+			Assert.AreEqual (route.Model, handler.Model, "#C1-2");
+
+			request.SetProperty ("AppRelativeCurrentExecutionFilePath", "~/BarTable/List.aspx");
+			rd = route.GetRouteData (wrapper);
+			Assert.IsNotNull (rd, "#D1");
+			Assert.IsNotNull (handler.Model, "#D1-1");
+			Assert.AreEqual (route.Model, handler.Model, "#D1-2");
+		}
+
+		[Test]
+		public void SetRequestMetaTable ()
+		{
+			MetaModel m = Utils.CommonInitialize ();
+			var route = RouteTable.Routes[0] as DynamicDataRoute;
+			MetaTable t = m.Tables[TestDataContext.TableFooDisplayName];
+			Assert.IsNotNull (t, "#A1");
+
+			// And following the tradition... [drum roll] - NO NULL CHECK!
+			AssertExtensions.Throws<NullReferenceException> (() => {
+				DynamicDataRouteHandler.SetRequestMetaTable (null, t);
+			}, "#A2");
+
+			DynamicDataRouteHandler.SetRequestMetaTable (HttpContext.Current, t);
+			MetaTable t2 = DynamicDataRouteHandler.GetRequestMetaTable (HttpContext.Current);
+			Assert.IsNotNull (t2, "#A3");
+			Assert.AreEqual (t, t2, "#A3-1");
+
+			DynamicDataRouteHandler.SetRequestMetaTable (HttpContext.Current, null);
+			t2 = DynamicDataRouteHandler.GetRequestMetaTable (HttpContext.Current);
+			Assert.IsNull (t2, "#A4");
+		}
 	}
 }

+ 41 - 7
mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicDataRouteTest.cs

@@ -67,6 +67,7 @@ namespace MonoTests.System.Web.DynamicData
 		{
 			var dynamicModelProvider = new DynamicDataContainerModelProvider (typeof (TestDataContainer<TestDataContext>));
 			Utils.RegisterContext (dynamicModelProvider, new ContextConfiguration () { ScaffoldAllTables = true });
+			Utils.RegisterContext (typeof (MyDataContext3));
 		}
 
 		[Test]
@@ -91,13 +92,16 @@ namespace MonoTests.System.Web.DynamicData
 			Assert.IsNull (r.Table, "#3");
 			Assert.IsNull (r.ViewName, "#4");
 			Assert.IsNotNull (r.RouteHandler, "#5");
-			Assert.IsNull (r.RouteHandler.Model, "#6");
+			Assert.IsNotNull (r.Model, "#6");
 			Assert.IsNull (r.RouteHandler.Model, "#7"); // irrelevant to route's MetaModel
 		}
 
 		[Test]
 		[ExpectedException (typeof (ArgumentNullException))]
 		[Category ("NotDotNet")] // .NET throws NRE. yuck.
+#if TARGET_DOTNET
+		[Ignore ("Throws a NREX on .NET...")]
+#endif
 		public void GetActionFromRouteDataNullArg ()
 		{
 			new DynamicDataRoute ("x").GetActionFromRouteData (null);
@@ -126,6 +130,9 @@ namespace MonoTests.System.Web.DynamicData
 		[Test]
 		[ExpectedException (typeof (ArgumentNullException))]
 		[Category ("NotDotNet")] // .NET throws NRE. yuck.
+#if TARGET_DOTNET
+		[Ignore ("Throws a NREX on .NET...")]
+#endif
 		public void GetTableFromRouteDataNullArg ()
 		{
 			new DynamicDataRoute ("x").GetTableFromRouteData (null);
@@ -153,24 +160,51 @@ namespace MonoTests.System.Web.DynamicData
 		}
 
 		[Test]
-		[Category ("NotWorking")]
 		public void GetTableFromRouteData3 ()
 		{
 			var r = new DynamicDataRoute ("x");
-			r.Model.RegisterContext (typeof (MyDataContext3));
 			var rd = new RouteData ();
 			rd.Values["Table"] = "FooTable";
 			var t = r.GetTableFromRouteData (rd);
 		}
 
 		[Test]
-		[Ignore ("it requires working HttpContext, and it's somehow not working on both mono and .net")]
 		public void GetRouteData ()
 		{
 			var r = new DynamicDataRoute ("{table}/{action}.aspx");
-			HttpContext.Current = new HttpContext (new MyHttpWorkerRequest ());
-			RouteData rd = r.GetRouteData (new HttpContextStub ("~/FooTable/List.aspx", String.Empty));
-			Assert.IsNotNull (rd.RouteHandler, "#1");
+
+			// We need one which overloads CreateHandler
+			r.RouteHandler = new MyDynamicDataRouteHandler ();
+
+			var wrapper = new MyHttpContextWrapper ();
+			var request = wrapper.Request as MyHttpRequestWrapper;
+			request.SetProperty ("AppRelativeCurrentExecutionFilePath", "~/NoSuchTable/List.aspx");
+			request.SetProperty ("PathInfo", String.Empty);
+
+			// This must be non-null because DynamicData doesn't care to check whether the returned
+			// value is null or not...
+			request.SetProperty ("QueryString", new NameValueCollection ());
+
+			// It appears .NET checks whether the indicated table exists - if not, GetRouteData will return
+			// null (even though the Route class will find a match)
+			RouteData rd = r.GetRouteData (wrapper);
+			Assert.IsNull (rd, "#A1");
+
+			request.SetProperty ("AppRelativeCurrentExecutionFilePath", "~/BazTable/List.aspx");
+			rd = r.GetRouteData (wrapper);
+			Assert.IsNotNull (rd, "#B1");
+		}
+
+		[Test]
+		public void RouteHandler ()
+		{
+			var r = new DynamicDataRoute ("{table}/{action}.aspx");
+
+			Assert.IsNotNull (r.RouteHandler, "#A1");
+			Assert.AreEqual (typeof (DynamicDataRouteHandler), r.RouteHandler.GetType (), "#A1-1");
+
+			r.RouteHandler = null;
+			Assert.IsNull (r.RouteHandler, "#A2");
 		}
 
 		[Test]

+ 20 - 0
mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaModelTest.cs

@@ -87,6 +87,26 @@ namespace MonoTests.System.Web.DynamicData
 			Assert.AreEqual (typeof (FieldTemplateFactory), model.FieldTemplateFactory.GetType (), "#B3");
 		}
 
+		[Test]
+		public void DynamicDataFolderVirtualPath ()
+		{
+			var model = new MetaModel ();
+
+			Assert.AreEqual ("~/DynamicData/", model.DynamicDataFolderVirtualPath, "#A1");
+			model.DynamicDataFolderVirtualPath = null;
+			Assert.AreEqual ("~/DynamicData/", model.DynamicDataFolderVirtualPath, "#A2");
+			model.DynamicDataFolderVirtualPath = String.Empty;
+			Assert.AreEqual (String.Empty, model.DynamicDataFolderVirtualPath, "#A3");
+			model.DynamicDataFolderVirtualPath = "~/FolderNoTrailingSlash";
+			Assert.AreEqual ("~/FolderNoTrailingSlash/", model.DynamicDataFolderVirtualPath, "#A4");
+			model.DynamicDataFolderVirtualPath = "AnotherFolder";
+			Assert.AreEqual ("AnotherFolder/", model.DynamicDataFolderVirtualPath, "#A5");
+			model.DynamicDataFolderVirtualPath = "/YetAnotherFolder";
+			Assert.AreEqual ("/YetAnotherFolder/", model.DynamicDataFolderVirtualPath, "#A6");
+			model.DynamicDataFolderVirtualPath = null;
+			Assert.AreEqual ("~/DynamicData/", model.DynamicDataFolderVirtualPath, "#A7");
+		}
+
 		[Test]
 		[ExpectedException (typeof (ArgumentNullException))]
 		public void GetTableNull ()