5 // Atsushi Enomoto <atsushi@ximian.com>
6 // Marek Habersack <mhabersack@novell.com>
8 // Copyright (C) 2008 Novell Inc. http://novell.com
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.Collections.ObjectModel;
35 using System.Collections.Specialized;
36 using System.ComponentModel;
37 using System.Globalization;
38 using System.Security.Permissions;
39 using System.Security.Principal;
40 using System.Web.Caching;
41 using System.Web.DynamicData.ModelProviders;
43 namespace System.Web.DynamicData
45 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
46 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47 public class MetaModel
49 const string DEFAULT_DYNAMIC_DATA_VIRTUAL_FOLDER_PATH = "~/DynamicData/";
51 static object registered_models_lock = new object ();
53 static MetaModel default_model;
54 static Exception registration_exception;
55 static Dictionary<Type, MetaModel> registered_models;
57 string dynamicDataFolderVirtualPath;
59 public static MetaModel Default {
60 get { return default_model; }
61 internal set { default_model = value; }
64 public static MetaModel GetModel (Type contextType)
66 if (contextType == null)
67 throw new ArgumentNullException ("contextType");
70 if (!TryGetModel (contextType, out m))
71 throw new InvalidOperationException (String.Format ("Type '{0}' is not registered as a MetaModel", contextType));
76 public static void ResetRegistrationException ()
78 registration_exception = null;
83 if (default_model == null)
86 FieldTemplateFactory ftf = new FieldTemplateFactory ();
87 ftf.Initialize (this);
88 FieldTemplateFactory = ftf;
90 Tables = new ReadOnlyCollection<MetaTable> (new MetaTable [0]);
91 VisibleTables = new List<MetaTable> ();
94 public string DynamicDataFolderVirtualPath {
96 if (dynamicDataFolderVirtualPath == null)
97 return DEFAULT_DYNAMIC_DATA_VIRTUAL_FOLDER_PATH;
99 return dynamicDataFolderVirtualPath;
103 if (!String.IsNullOrEmpty (value))
104 dynamicDataFolderVirtualPath = VirtualPathUtility.AppendTrailingSlash (value);
106 dynamicDataFolderVirtualPath = value;
110 public IFieldTemplateFactory FieldTemplateFactory { get; set; }
112 public ReadOnlyCollection<MetaTable> Tables { get; private set; }
114 public List<MetaTable> VisibleTables { get; private set; }
116 void CheckRegistrationError ()
118 if (registration_exception != null)
119 throw new InvalidOperationException ("An error occured during context model registration", registration_exception);
122 public string GetActionPath (string tableName, string action, object row)
124 return GetTable (tableName).GetActionPath (action, row);
127 internal static void GetDataFieldAttribute <T> (AttributeCollection attributes, ref T backingField) where T: Attribute
129 if (backingField != null)
132 foreach (Attribute attr in attributes) {
133 if (attr == null || !typeof (T).IsAssignableFrom (attr.GetType ()))
136 backingField = attr as T;
141 public MetaTable GetTable (string uniqueTableName)
144 if (TryGetTable (uniqueTableName, out mt))
146 throw new ArgumentException (String.Format ("Table '{0}' does not exist in registered context", uniqueTableName));
149 public MetaTable GetTable (Type entityType)
151 if (entityType == null)
152 throw new ArgumentNullException ("entityType");
154 foreach (var t in Tables) {
155 if (t.EntityType == entityType)
159 throw new ArgumentException (String.Format ("Entity type '{0}' does not exist in registered context", entityType));
162 public MetaTable GetTable (string tableName, Type contextType)
164 if (tableName == null)
165 throw new ArgumentNullException ("tableName");
168 if (contextType != null && !TryGetModel (contextType, out model))
169 throw new ArgumentException ("Unknown context type '" + contextType + "'. This context type has not been registered.");
171 return GetModel (contextType).GetTable (tableName);
174 internal static ICustomTypeDescriptor GetTypeDescriptor (Type type)
176 return TypeDescriptor.GetProvider (type).GetTypeDescriptor (type);
179 public void RegisterContext (Func<object> contextFactory)
181 RegisterContext (contextFactory, null);
184 public void RegisterContext (Type contextType)
186 RegisterContext (contextType, null);
189 public void RegisterContext (DataModelProvider dataModelProvider)
191 RegisterContext (dataModelProvider, null);
194 public void RegisterContext (Type contextType, ContextConfiguration configuration)
196 if (contextType == null)
197 throw new ArgumentNullException ("contextType");
198 CheckRegistrationError ();
199 RegisterContext (() => Activator.CreateInstance (contextType), configuration);
200 RegisterModel (contextType, this, configuration);
203 public void RegisterContext (Func<object> contextFactory, ContextConfiguration configuration)
205 if (contextFactory == null)
206 throw new ArgumentNullException ("contextFactory");
207 CheckRegistrationError ();
209 // FIXME: entity framework support is not done.
210 RegisterContextCore (new DLinqDataModelProvider (contextFactory), configuration);
211 } catch (Exception ex) {
212 registration_exception = ex;
217 public void RegisterContext (DataModelProvider dataModelProvider, ContextConfiguration configuration)
219 if (dataModelProvider == null)
220 throw new ArgumentNullException ("dataModelProvider");
221 CheckRegistrationError ();
223 RegisterContextCore (dataModelProvider, configuration);
224 } catch (Exception ex) {
225 registration_exception = ex;
230 void RegisterContextCore (DataModelProvider dataModelProvider, ContextConfiguration configuration)
232 RegisterModel (dataModelProvider.ContextType, this, configuration);
234 var l = new List<MetaTable> (Tables);
235 foreach (var t in dataModelProvider.Tables)
236 l.Add (new MetaTable (this, t, configuration));
238 Tables = new ReadOnlyCollection<MetaTable> (l);
240 foreach (MetaTable t in l)
246 static void RegisterModel (Type contextType, MetaModel model, ContextConfiguration configuration)
248 lock (registered_models_lock) {
249 if (registered_models == null)
250 registered_models = new Dictionary <Type, MetaModel> ();
252 if (registered_models.ContainsKey (contextType))
255 registered_models.Add (contextType, model);
257 RegisterTypeDescriptionProvider (contextType, configuration);
260 static void RegisterTypeDescriptionProvider (Type type, ContextConfiguration config)
262 Func <Type, TypeDescriptionProvider> factory = config == null ? null : config.MetadataProviderFactory;
263 if (config == null || factory == null)
266 TypeDescriptionProvider provider = factory (type);
267 if (provider == null)
270 TypeDescriptor.AddProvider (provider, type);
273 public bool TryGetTable (string uniqueTableName, out MetaTable table)
275 if (uniqueTableName == null)
276 throw new ArgumentNullException ("uniqueTableName");
277 foreach (var t in Tables)
278 if (t.Name == uniqueTableName) {
286 static bool TryGetModel (Type contextType, out MetaModel model)
289 if (registered_models != null && registered_models.TryGetValue (contextType, out model))
290 return model != null;