disable broken tests on net_4_0
[mcs.git] / class / System.Web.DynamicData / System.Web.DynamicData / DynamicDataRouteHandler.cs
blob0fe003fbc908d7fc478ebb1b6e030b493995f6a2
1 //
2 // DynamicDataRouteHandler.cs
3 //
4 // Authors:
5 // Atsushi Enomoto <atsushi@ximian.com>
6 // Marek Habersack <mhabersack@novell.com>
7 //
8 // Copyright (C) 2008-2009 Novell Inc. http://novell.com
9 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.Collections.Specialized;
35 using System.Data.Linq.Mapping;
36 using System.Globalization;
37 using System.Security.Permissions;
38 using System.Security.Principal;
39 using System.Threading;
40 using System.Web.Caching;
41 using System.Web.Compilation;
42 using System.Web.Hosting;
43 using System.Web.Routing;
44 using System.Web.UI;
46 namespace System.Web.DynamicData
48 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
49 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
50 public class DynamicDataRouteHandler : IRouteHandler
52 static ReaderWriterLockSlim contextsLock = new ReaderWriterLockSlim ();
54 static Dictionary <HttpContext, RouteContext> contexts = new Dictionary <HttpContext, RouteContext> ();
55 Dictionary <RouteContext, IHttpHandler> handlers;
57 Dictionary <RouteContext, IHttpHandler> Handlers {
58 get {
59 if (handlers == null)
60 handlers = new Dictionary <RouteContext, IHttpHandler> ();
62 return handlers;
66 static RouteContext GetOrCreateRouteContext (HttpContext httpContext)
68 RouteContext rc = null;
69 bool locked = false;
70 try {
71 contextsLock.EnterReadLock ();
72 locked = true;
73 if (contexts.TryGetValue (httpContext, out rc) && rc != null)
74 return rc;
75 } finally {
76 if (locked)
77 contextsLock.ExitReadLock ();
80 locked = false;
81 try {
82 contextsLock.EnterWriteLock ();
83 locked = true;
84 rc = MakeRouteContext (new RequestContext (new HttpContextWrapper (httpContext), new RouteData ()), null, null, null);
85 contexts.Add (httpContext, rc);
86 } finally {
87 if (locked)
88 contextsLock.ExitWriteLock ();
91 return rc;
94 public static RequestContext GetRequestContext (HttpContext httpContext)
96 if (httpContext == null)
97 throw new ArgumentNullException ("httpContext");
99 return GetOrCreateRouteContext (httpContext).Context;
102 public static MetaTable GetRequestMetaTable (HttpContext httpContext)
104 if (httpContext == null)
105 throw new ArgumentNullException ("httpContext");
107 RouteContext rc;
108 bool locked = false;
109 try {
110 contextsLock.EnterReadLock ();
111 locked = true;
112 if (contexts.TryGetValue (httpContext, out rc) && rc != null)
113 return rc.Table;
114 } finally {
115 if (locked)
116 contextsLock.ExitReadLock ();
119 return null;
122 public static void SetRequestMetaTable (HttpContext httpContext, MetaTable table)
124 // And tradiationally... some .NET emulation code
125 if (httpContext == null)
126 throw new NullReferenceException ();
128 GetOrCreateRouteContext (httpContext).Table = table;
131 public DynamicDataRouteHandler ()
135 public MetaModel Model { get; internal set; }
137 [MonoTODO ("Needs a working test")]
138 public virtual IHttpHandler CreateHandler (DynamicDataRoute route, MetaTable table, string action)
140 // .NET bug emulation mode
141 if (route == null || table == null || action == null)
142 throw new NullReferenceException ();
144 // NOTE: all code below is a result of guessing as no tests succeed for this
145 // call so far!
147 IHttpHandler ret = null;
149 // Give custom pages a chance
150 string viewName = String.IsNullOrEmpty (action) ? route.ViewName : action;
151 string path = GetCustomPageVirtualPath (table, viewName);
153 // Pages might be in app resources, need to use a VPP
154 VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
156 if (vpp != null && vpp.FileExists (path))
157 ret = BuildManager.CreateInstanceFromVirtualPath (path, typeof (Page)) as IHttpHandler;
159 if (ret != null)
160 return ret;
162 path = GetScaffoldPageVirtualPath (table, viewName);
163 if (vpp != null && vpp.FileExists (path))
164 ret = BuildManager.CreateInstanceFromVirtualPath (path, typeof (Page)) as IHttpHandler;
166 return ret;
169 protected virtual string GetCustomPageVirtualPath (MetaTable table, string viewName)
171 // No such checks are made in .NET, we won't follow the pattern...
172 MetaModel model = Model;
173 if (table == null || model == null)
174 throw new NullReferenceException (); // yuck
176 // Believe it or not, this is what .NET does - pass a null/empty viewName
177 // and you get /.aspx at the end...
178 return model.DynamicDataFolderVirtualPath + "CustomPages/" + table.Name + "/" + viewName + ".aspx";
181 protected virtual string GetScaffoldPageVirtualPath (MetaTable table, string viewName)
183 // No such checks are made in .NET, we won't follow the pattern...
184 MetaModel model = Model;
185 if (table == null || model == null)
186 throw new NullReferenceException (); // yuck
188 // Believe it or not, this is what .NET does - pass a null/empty viewName
189 // and you get /.aspx at the end...
190 return model.DynamicDataFolderVirtualPath + "PageTemplates/" + viewName + ".aspx";
193 IHttpHandler IRouteHandler.GetHttpHandler (RequestContext requestContext)
195 if (requestContext == null)
196 throw new ArgumentNullException ("requestContext");
197 RouteData rd = requestContext.RouteData;
198 var dr = rd.Route as DynamicDataRoute;
199 if (dr == null)
200 throw new ArgumentException ("The argument RequestContext does not have DynamicDataRoute in its RouteData");
201 string action = dr.GetActionFromRouteData (rd);
202 MetaTable mt = dr.GetTableFromRouteData (rd);
203 RouteContext rc = MakeRouteContext (requestContext, dr, action, mt);
204 IHttpHandler h;
206 Dictionary <RouteContext, IHttpHandler> handlers = Handlers;
207 if (handlers.TryGetValue (rc, out h))
208 return h;
209 h = CreateHandler (dr, mt, action);
210 handlers.Add (rc, h);
211 return h;
214 static RouteContext MakeRouteContext (RequestContext context, DynamicDataRoute route, string action, MetaTable table)
216 RouteData rd = null;
218 if (route == null) {
219 rd = context.RouteData;
220 route = rd.Route as DynamicDataRoute;
223 if (route != null) {
224 if (action == null) {
225 if (rd == null)
226 rd = context.RouteData;
227 action = route.GetActionFromRouteData (rd);
230 if (table == null) {
231 if (rd == null)
232 rd = context.RouteData;
234 table = route.GetTableFromRouteData (rd);
238 return new RouteContext () {
239 Route = route,
240 Action = action,
241 Table = table,
242 Context = context};
245 sealed class RouteContext
247 public DynamicDataRoute Route;
248 public string Action;
249 public MetaTable Table;
250 public RequestContext Context;
252 public RouteContext ()
256 public override bool Equals (object obj)
258 RouteContext other = obj as RouteContext;
259 return other.Route == Route & other.Action == Action && other.Table == Table && other.Context == Context;
262 public override int GetHashCode ()
264 return (Route != null ? Route.GetHashCode () << 27 : 0) +
265 (Action != null ? Action.GetHashCode () << 19 : 0) +
266 (Table != null ? Table.GetHashCode () << 9 : 0) +
267 (Context != null ? Context.GetHashCode () : 0);