PageRenderTime 71ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/src/System.Web.Http.OData/OData/Formatter/EdmLibHelpers.cs

https://github.com/huyq2002/aspnetwebstack
C# | 561 lines | 469 code | 70 blank | 22 comment | 116 complexity | bfeaeb63dcb4832c947c5ecd2e8ee41e MD5 | raw file
Possible License(s): Apache-2.0
  1. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  2. using System.Collections.Generic;
  3. using System.Data.Linq;
  4. using System.Diagnostics.Contracts;
  5. using System.Globalization;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Spatial;
  9. using System.Web.Http.Dispatcher;
  10. using System.Web.Http.OData.Properties;
  11. using System.Web.Http.OData.Query.Expressions;
  12. using System.Xml.Linq;
  13. using Microsoft.Data.Edm;
  14. using Microsoft.Data.Edm.Library;
  15. namespace System.Web.Http.OData.Formatter
  16. {
  17. internal static class EdmLibHelpers
  18. {
  19. private static readonly EdmCoreModel _coreModel = EdmCoreModel.Instance;
  20. private static readonly IAssembliesResolver _defaultAssemblyResolver = new DefaultAssembliesResolver();
  21. private static readonly Dictionary<Type, IEdmPrimitiveType> _builtInTypesMapping =
  22. new[]
  23. {
  24. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(string), GetPrimitiveType(EdmPrimitiveTypeKind.String)),
  25. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(bool), GetPrimitiveType(EdmPrimitiveTypeKind.Boolean)),
  26. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(bool?), GetPrimitiveType(EdmPrimitiveTypeKind.Boolean)),
  27. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(byte), GetPrimitiveType(EdmPrimitiveTypeKind.Byte)),
  28. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(byte?), GetPrimitiveType(EdmPrimitiveTypeKind.Byte)),
  29. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(DateTime), GetPrimitiveType(EdmPrimitiveTypeKind.DateTime)),
  30. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(DateTime?), GetPrimitiveType(EdmPrimitiveTypeKind.DateTime)),
  31. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(decimal), GetPrimitiveType(EdmPrimitiveTypeKind.Decimal)),
  32. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(decimal?), GetPrimitiveType(EdmPrimitiveTypeKind.Decimal)),
  33. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(double), GetPrimitiveType(EdmPrimitiveTypeKind.Double)),
  34. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(double?), GetPrimitiveType(EdmPrimitiveTypeKind.Double)),
  35. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(Guid), GetPrimitiveType(EdmPrimitiveTypeKind.Guid)),
  36. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(Guid?), GetPrimitiveType(EdmPrimitiveTypeKind.Guid)),
  37. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(short), GetPrimitiveType(EdmPrimitiveTypeKind.Int16)),
  38. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(short?), GetPrimitiveType(EdmPrimitiveTypeKind.Int16)),
  39. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(int), GetPrimitiveType(EdmPrimitiveTypeKind.Int32)),
  40. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(int?), GetPrimitiveType(EdmPrimitiveTypeKind.Int32)),
  41. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(long), GetPrimitiveType(EdmPrimitiveTypeKind.Int64)),
  42. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(long?), GetPrimitiveType(EdmPrimitiveTypeKind.Int64)),
  43. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(sbyte), GetPrimitiveType(EdmPrimitiveTypeKind.SByte)),
  44. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(sbyte?), GetPrimitiveType(EdmPrimitiveTypeKind.SByte)),
  45. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(float), GetPrimitiveType(EdmPrimitiveTypeKind.Single)),
  46. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(float?), GetPrimitiveType(EdmPrimitiveTypeKind.Single)),
  47. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(byte[]), GetPrimitiveType(EdmPrimitiveTypeKind.Binary)),
  48. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(Stream), GetPrimitiveType(EdmPrimitiveTypeKind.Stream)),
  49. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(Geography), GetPrimitiveType(EdmPrimitiveTypeKind.Geography)),
  50. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeographyPoint), GetPrimitiveType(EdmPrimitiveTypeKind.GeographyPoint)),
  51. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeographyLineString), GetPrimitiveType(EdmPrimitiveTypeKind.GeographyLineString)),
  52. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeographyPolygon), GetPrimitiveType(EdmPrimitiveTypeKind.GeographyPolygon)),
  53. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeographyCollection), GetPrimitiveType(EdmPrimitiveTypeKind.GeographyCollection)),
  54. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeographyMultiLineString), GetPrimitiveType(EdmPrimitiveTypeKind.GeographyMultiLineString)),
  55. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeographyMultiPoint), GetPrimitiveType(EdmPrimitiveTypeKind.GeographyMultiPoint)),
  56. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeographyMultiPolygon), GetPrimitiveType(EdmPrimitiveTypeKind.GeographyMultiPolygon)),
  57. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(Geometry), GetPrimitiveType(EdmPrimitiveTypeKind.Geometry)),
  58. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeometryPoint), GetPrimitiveType(EdmPrimitiveTypeKind.GeometryPoint)),
  59. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeometryLineString), GetPrimitiveType(EdmPrimitiveTypeKind.GeometryLineString)),
  60. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeometryPolygon), GetPrimitiveType(EdmPrimitiveTypeKind.GeometryPolygon)),
  61. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeometryCollection), GetPrimitiveType(EdmPrimitiveTypeKind.GeometryCollection)),
  62. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeometryMultiLineString), GetPrimitiveType(EdmPrimitiveTypeKind.GeometryMultiLineString)),
  63. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeometryMultiPoint), GetPrimitiveType(EdmPrimitiveTypeKind.GeometryMultiPoint)),
  64. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(GeometryMultiPolygon), GetPrimitiveType(EdmPrimitiveTypeKind.GeometryMultiPolygon)),
  65. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(TimeSpan), GetPrimitiveType(EdmPrimitiveTypeKind.Time)),
  66. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(TimeSpan?), GetPrimitiveType(EdmPrimitiveTypeKind.Time)),
  67. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(DateTimeOffset), GetPrimitiveType(EdmPrimitiveTypeKind.DateTimeOffset)),
  68. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(DateTimeOffset?), GetPrimitiveType(EdmPrimitiveTypeKind.DateTimeOffset)),
  69. // Keep the Binary and XElement in the end, since there are not the default mappings for Edm.Binary and Edm.String.
  70. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(XElement), GetPrimitiveType(EdmPrimitiveTypeKind.String)),
  71. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(Binary), GetPrimitiveType(EdmPrimitiveTypeKind.Binary)),
  72. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(ushort), GetPrimitiveType(EdmPrimitiveTypeKind.Int32)),
  73. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(ushort?), GetPrimitiveType(EdmPrimitiveTypeKind.Int32)),
  74. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(uint), GetPrimitiveType(EdmPrimitiveTypeKind.Int64)),
  75. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(uint?), GetPrimitiveType(EdmPrimitiveTypeKind.Int64)),
  76. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(ulong), GetPrimitiveType(EdmPrimitiveTypeKind.Int64)),
  77. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(ulong?), GetPrimitiveType(EdmPrimitiveTypeKind.Int64)),
  78. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(char[]), GetPrimitiveType(EdmPrimitiveTypeKind.String)),
  79. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(char), GetPrimitiveType(EdmPrimitiveTypeKind.String)),
  80. new KeyValuePair<Type, IEdmPrimitiveType>(typeof(char?), GetPrimitiveType(EdmPrimitiveTypeKind.String)),
  81. }
  82. .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
  83. public static IEdmType GetEdmType(this IEdmModel edmModel, Type clrType)
  84. {
  85. if (edmModel == null)
  86. {
  87. throw Error.ArgumentNull("edmModel");
  88. }
  89. if (clrType == null)
  90. {
  91. throw Error.ArgumentNull("clrType");
  92. }
  93. return GetEdmType(edmModel, clrType, testCollections: true);
  94. }
  95. private static IEdmType GetEdmType(IEdmModel edmModel, Type clrType, bool testCollections)
  96. {
  97. Contract.Assert(edmModel != null);
  98. Contract.Assert(clrType != null);
  99. IEdmPrimitiveType primitiveType = GetEdmPrimitiveTypeOrNull(clrType);
  100. if (primitiveType != null)
  101. {
  102. return primitiveType;
  103. }
  104. else
  105. {
  106. if (testCollections)
  107. {
  108. Type enumerableOfT = ExtractGenericInterface(clrType, typeof(IEnumerable<>));
  109. if (enumerableOfT != null)
  110. {
  111. Type elementClrType = enumerableOfT.GetGenericArguments()[0];
  112. // IEnumerable<SelectExpandWrapper<T>> is a collection of T.
  113. Type entityType;
  114. if (IsSelectExpandWrapper(elementClrType, out entityType))
  115. {
  116. elementClrType = entityType;
  117. }
  118. IEdmType elementType = GetEdmType(edmModel, elementClrType, testCollections: false);
  119. if (elementType != null)
  120. {
  121. return new EdmCollectionType(elementType.ToEdmTypeReference(IsNullable(elementClrType)));
  122. }
  123. }
  124. }
  125. // search for the ClrTypeAnnotation and return it if present
  126. IEdmType returnType =
  127. edmModel
  128. .SchemaElements
  129. .OfType<IEdmType>()
  130. .Select(edmType => new { EdmType = edmType, Annotation = edmModel.GetAnnotationValue<ClrTypeAnnotation>(edmType) })
  131. .Where(tuple => tuple.Annotation != null && tuple.Annotation.ClrType == clrType)
  132. .Select(tuple => tuple.EdmType)
  133. .SingleOrDefault();
  134. // default to the EdmType with the same name as the ClrType name
  135. returnType = returnType ?? edmModel.FindType(clrType.EdmFullName());
  136. if (clrType.BaseType != null)
  137. {
  138. // go up the inheritance tree to see if we have a mapping defined for the base type.
  139. returnType = returnType ?? GetEdmType(edmModel, clrType.BaseType, testCollections);
  140. }
  141. return returnType;
  142. }
  143. }
  144. public static IEdmTypeReference GetEdmTypeReference(this IEdmModel edmModel, Type clrType)
  145. {
  146. IEdmType edmType = edmModel.GetEdmType(clrType);
  147. if (edmType != null)
  148. {
  149. bool isNullable = IsNullable(clrType);
  150. return ToEdmTypeReference(edmType, isNullable);
  151. }
  152. return null;
  153. }
  154. public static IEdmTypeReference ToEdmTypeReference(this IEdmType edmType, bool isNullable)
  155. {
  156. Contract.Assert(edmType != null);
  157. switch (edmType.TypeKind)
  158. {
  159. case EdmTypeKind.Collection:
  160. return new EdmCollectionTypeReference(edmType as IEdmCollectionType, isNullable);
  161. case EdmTypeKind.Complex:
  162. return new EdmComplexTypeReference(edmType as IEdmComplexType, isNullable);
  163. case EdmTypeKind.Entity:
  164. return new EdmEntityTypeReference(edmType as IEdmEntityType, isNullable);
  165. case EdmTypeKind.EntityReference:
  166. return new EdmEntityReferenceTypeReference(edmType as IEdmEntityReferenceType, isNullable);
  167. case EdmTypeKind.Enum:
  168. return new EdmEnumTypeReference(edmType as IEdmEnumType, isNullable);
  169. case EdmTypeKind.Primitive:
  170. return _coreModel.GetPrimitive((edmType as IEdmPrimitiveType).PrimitiveKind, isNullable);
  171. case EdmTypeKind.Row:
  172. return new EdmRowTypeReference(edmType as IEdmRowType, isNullable);
  173. default:
  174. throw Error.NotSupported(SRResources.EdmTypeNotSupported, edmType.ToTraceString());
  175. }
  176. }
  177. public static IEdmCollectionType GetCollection(this IEdmEntityType entityType)
  178. {
  179. return new EdmCollectionType(new EdmEntityTypeReference(entityType, isNullable: false));
  180. }
  181. private static bool CanBindTo(this IEdmFunctionImport function, IEdmEntityType entity)
  182. {
  183. if (function == null)
  184. {
  185. throw Error.ArgumentNull("function");
  186. }
  187. if (entity == null)
  188. {
  189. throw Error.ArgumentNull("entity");
  190. }
  191. if (!function.IsBindable)
  192. {
  193. return false;
  194. }
  195. // The binding parameter is the first parameter by convention
  196. IEdmFunctionParameter bindingParameter = function.Parameters.FirstOrDefault();
  197. if (bindingParameter == null)
  198. {
  199. return false;
  200. }
  201. IEdmEntityType bindingParameterType = bindingParameter.Type.Definition as IEdmEntityType;
  202. if (bindingParameterType == null)
  203. {
  204. return false;
  205. }
  206. return entity.IsOrInheritsFrom(bindingParameterType);
  207. }
  208. private static bool CanBindTo(this IEdmFunctionImport function, IEdmCollectionType collection)
  209. {
  210. if (function == null)
  211. {
  212. throw Error.ArgumentNull("function");
  213. }
  214. if (collection == null)
  215. {
  216. throw Error.ArgumentNull("collection");
  217. }
  218. if (!function.IsBindable)
  219. {
  220. return false;
  221. }
  222. // The binding parameter is the first parameter by convention
  223. IEdmFunctionParameter bindingParameter = function.Parameters.FirstOrDefault();
  224. if (bindingParameter == null)
  225. {
  226. return false;
  227. }
  228. IEdmCollectionType bindingParameterType = bindingParameter.Type.Definition as IEdmCollectionType;
  229. if (bindingParameterType == null)
  230. {
  231. return false;
  232. }
  233. IEdmEntityType bindingParameterElementType = bindingParameterType.ElementType.Definition as IEdmEntityType;
  234. IEdmEntityType entity = collection.ElementType.Definition as IEdmEntityType;
  235. if (bindingParameterElementType == null || entity == null)
  236. {
  237. return false;
  238. }
  239. return entity.IsOrInheritsFrom(bindingParameterElementType);
  240. }
  241. public static IEnumerable<IEdmFunctionImport> GetMatchingActions(this IEnumerable<IEdmFunctionImport> functions, string actionIdentifier)
  242. {
  243. if (functions == null)
  244. {
  245. throw Error.ArgumentNull("functions");
  246. }
  247. if (actionIdentifier == null)
  248. {
  249. throw Error.ArgumentNull("actionIdentifier");
  250. }
  251. string[] nameParts = actionIdentifier.Split('.');
  252. Contract.Assert(nameParts.Length != 0);
  253. if (nameParts.Length == 1)
  254. {
  255. // Name
  256. string name = nameParts[0];
  257. return functions.Where(f => f.IsSideEffecting && f.Name == name);
  258. }
  259. else if (nameParts.Length == 2)
  260. {
  261. // Container.Name
  262. string name = nameParts[nameParts.Length - 1];
  263. string container = nameParts[nameParts.Length - 2];
  264. return functions.Where(f => f.IsSideEffecting && f.Name == name && f.Container.Name == container);
  265. }
  266. else
  267. {
  268. // Namespace.Container.Name
  269. string name = nameParts[nameParts.Length - 1];
  270. string container = nameParts[nameParts.Length - 2];
  271. string nspace = String.Join(".", nameParts.Take(nameParts.Length - 2));
  272. return functions.Where(f => f.IsSideEffecting && f.Name == name && f.Container.Name == container && f.Container.Namespace == nspace);
  273. }
  274. }
  275. public static IEdmFunctionImport FindBindableAction(this IEnumerable<IEdmFunctionImport> functions,
  276. IEdmEntityType entityType, string actionIdentifier)
  277. {
  278. if (functions == null)
  279. {
  280. throw Error.ArgumentNull("functions");
  281. }
  282. if (entityType == null)
  283. {
  284. throw Error.ArgumentNull("entityType");
  285. }
  286. if (actionIdentifier == null)
  287. {
  288. throw Error.ArgumentNull("actionIdentifier");
  289. }
  290. IEnumerable<IEdmFunctionImport> matches =
  291. functions.GetMatchingActions(actionIdentifier).Where(fi => fi.CanBindTo(entityType));
  292. return FindBest(actionIdentifier, matches, entityType, isCollection: false);
  293. }
  294. // Performs overload resolution between a set of matching bindable actions. OData protocol ensures that there
  295. // cannot be multiple bindable actions with same name and different sets of non-bindable paramters.
  296. // The resolution logic is simple and is dependant only on the binding parameter and chooses the action that is defined
  297. // closest to the binding parameter in the inheritance hierarchy.
  298. private static IEdmFunctionImport FindBest(string actionIdentifier, IEnumerable<IEdmFunctionImport> bindableActions,
  299. IEdmEntityType bindingParameterType, bool isCollection)
  300. {
  301. if (bindingParameterType == null)
  302. {
  303. return null;
  304. }
  305. List<IEdmFunctionImport> actionsBoundToThisType = new List<IEdmFunctionImport>();
  306. foreach (IEdmFunctionImport action in bindableActions)
  307. {
  308. IEdmType actionParameterType = action.Parameters.First().Type.Definition;
  309. if (isCollection)
  310. {
  311. actionParameterType = ((IEdmCollectionType)actionParameterType).ElementType.Definition;
  312. }
  313. if (actionParameterType == bindingParameterType)
  314. {
  315. actionsBoundToThisType.Add(action);
  316. }
  317. }
  318. if (actionsBoundToThisType.Count > 1)
  319. {
  320. throw Error.Argument(
  321. "actionIdentifier",
  322. SRResources.ActionResolutionFailed,
  323. actionIdentifier,
  324. String.Join(", ", actionsBoundToThisType.Select(match => match.Container.FullName() + "." + match.Name)));
  325. }
  326. else if (actionsBoundToThisType.Count == 1)
  327. {
  328. return actionsBoundToThisType[0];
  329. }
  330. else
  331. {
  332. return FindBest(actionIdentifier, bindableActions, bindingParameterType.BaseEntityType(), isCollection);
  333. }
  334. }
  335. public static IEdmFunctionImport FindBindableAction(this IEnumerable<IEdmFunctionImport> functions,
  336. IEdmCollectionType collectionType, string actionIdentifier)
  337. {
  338. if (functions == null)
  339. {
  340. throw Error.ArgumentNull("functions");
  341. }
  342. if (collectionType == null)
  343. {
  344. throw Error.ArgumentNull("collectionType");
  345. }
  346. if (actionIdentifier == null)
  347. {
  348. throw Error.ArgumentNull("actionIdentifier");
  349. }
  350. IEnumerable<IEdmFunctionImport> matches =
  351. functions.GetMatchingActions(actionIdentifier).Where(fi => fi.CanBindTo(collectionType));
  352. IEdmEntityType elementType = (IEdmEntityType)collectionType.ElementType.Definition;
  353. return FindBest(actionIdentifier, matches, elementType, isCollection: true);
  354. }
  355. public static Type GetClrType(IEdmTypeReference edmTypeReference, IEdmModel edmModel)
  356. {
  357. return GetClrType(edmTypeReference, edmModel, _defaultAssemblyResolver);
  358. }
  359. public static Type GetClrType(IEdmTypeReference edmTypeReference, IEdmModel edmModel, IAssembliesResolver assembliesResolver)
  360. {
  361. if (edmTypeReference == null)
  362. {
  363. throw Error.ArgumentNull("edmTypeReference");
  364. }
  365. Type primitiveClrType = _builtInTypesMapping
  366. .Where(kvp => edmTypeReference.Definition.IsEquivalentTo(kvp.Value) && (!edmTypeReference.IsNullable || IsNullable(kvp.Key)))
  367. .Select(kvp => kvp.Key)
  368. .FirstOrDefault();
  369. if (primitiveClrType != null)
  370. {
  371. return primitiveClrType;
  372. }
  373. else
  374. {
  375. return GetClrType(edmTypeReference.Definition, edmModel, assembliesResolver);
  376. }
  377. }
  378. public static Type GetClrType(IEdmType edmType, IEdmModel edmModel)
  379. {
  380. return GetClrType(edmType, edmModel, _defaultAssemblyResolver);
  381. }
  382. public static Type GetClrType(IEdmType edmType, IEdmModel edmModel, IAssembliesResolver assembliesResolver)
  383. {
  384. IEdmSchemaType edmSchemaType = edmType as IEdmSchemaType;
  385. Contract.Assert(edmSchemaType != null);
  386. ClrTypeAnnotation annotation = edmModel.GetAnnotationValue<ClrTypeAnnotation>(edmSchemaType);
  387. if (annotation != null)
  388. {
  389. return annotation.ClrType;
  390. }
  391. string typeName = edmSchemaType.FullName();
  392. IEnumerable<Type> matchingTypes = GetMatchingTypes(typeName, assembliesResolver);
  393. if (matchingTypes.Count() > 1)
  394. {
  395. throw Error.Argument("edmTypeReference", SRResources.MultipleMatchingClrTypesForEdmType,
  396. typeName, String.Join(",", matchingTypes.Select(type => type.AssemblyQualifiedName)));
  397. }
  398. edmModel.SetAnnotationValue<ClrTypeAnnotation>(edmSchemaType, new ClrTypeAnnotation(matchingTypes.SingleOrDefault()));
  399. return matchingTypes.SingleOrDefault();
  400. }
  401. public static IEdmPrimitiveType GetEdmPrimitiveTypeOrNull(Type clrType)
  402. {
  403. Type underlyingType = Nullable.GetUnderlyingType(clrType) ?? clrType;
  404. if (underlyingType.IsEnum)
  405. {
  406. // Enums are treated as strings
  407. clrType = typeof(string);
  408. }
  409. IEdmPrimitiveType primitiveType;
  410. return _builtInTypesMapping.TryGetValue(clrType, out primitiveType) ? primitiveType : null;
  411. }
  412. public static IEdmPrimitiveTypeReference GetEdmPrimitiveTypeReferenceOrNull(Type clrType)
  413. {
  414. IEdmPrimitiveType primitiveType = GetEdmPrimitiveTypeOrNull(clrType);
  415. return primitiveType != null ? _coreModel.GetPrimitive(primitiveType.PrimitiveKind, IsNullable(clrType)) : null;
  416. }
  417. // figures out if the given clr type is nonstandard edm primitive like uint, ushort, char[] etc.
  418. // and returns the corresponding clr type to which we map like uint => long.
  419. public static Type IsNonstandardEdmPrimitive(Type type, out bool isNonstandardEdmPrimitive)
  420. {
  421. IEdmPrimitiveTypeReference edmType = GetEdmPrimitiveTypeReferenceOrNull(type);
  422. if (edmType == null)
  423. {
  424. isNonstandardEdmPrimitive = false;
  425. return type;
  426. }
  427. Type reverseLookupClrType = GetClrType(edmType, EdmCoreModel.Instance);
  428. isNonstandardEdmPrimitive = (type != reverseLookupClrType);
  429. return reverseLookupClrType;
  430. }
  431. // Mangle the invalid EDM literal Type.FullName (System.Collections.Generic.IEnumerable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]])
  432. // to a valid EDM literal (the C# type name IEnumerable<int>).
  433. public static string EdmName(this Type clrType)
  434. {
  435. // We cannot use just Type.Name here as it doesn't work for generic types.
  436. return MangleClrTypeName(clrType);
  437. }
  438. public static string EdmFullName(this Type clrType)
  439. {
  440. return String.Format(CultureInfo.InvariantCulture, "{0}.{1}", clrType.Namespace, clrType.EdmName());
  441. }
  442. private static IEdmPrimitiveType GetPrimitiveType(EdmPrimitiveTypeKind primitiveKind)
  443. {
  444. return _coreModel.GetPrimitiveType(primitiveKind);
  445. }
  446. public static bool IsNullable(Type type)
  447. {
  448. return !type.IsValueType || Nullable.GetUnderlyingType(type) != null;
  449. }
  450. private static bool IsSelectExpandWrapper(Type type, out Type entityType)
  451. {
  452. if (type == null)
  453. {
  454. entityType = null;
  455. return false;
  456. }
  457. if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(SelectExpandWrapper<>))
  458. {
  459. entityType = type.GetGenericArguments()[0];
  460. return true;
  461. }
  462. return IsSelectExpandWrapper(type.BaseType, out entityType);
  463. }
  464. private static Type ExtractGenericInterface(Type queryType, Type interfaceType)
  465. {
  466. Func<Type, bool> matchesInterface = t => t.IsGenericType && t.GetGenericTypeDefinition() == interfaceType;
  467. return matchesInterface(queryType) ? queryType : queryType.GetInterfaces().FirstOrDefault(matchesInterface);
  468. }
  469. private static IEnumerable<Type> GetMatchingTypes(string edmFullName, IAssembliesResolver assembliesResolver)
  470. {
  471. return TypeHelper.GetLoadedTypes(assembliesResolver).Where(t => t.IsPublic && t.EdmFullName() == edmFullName);
  472. }
  473. // TODO (workitem 336): Support nested types and anonymous types.
  474. private static string MangleClrTypeName(Type type)
  475. {
  476. Contract.Assert(type != null);
  477. if (!type.IsGenericType)
  478. {
  479. return type.Name;
  480. }
  481. else
  482. {
  483. return String.Format(
  484. CultureInfo.InvariantCulture,
  485. "{0}Of{1}",
  486. type.Name.Replace('`', '_'),
  487. String.Join("_", type.GetGenericArguments().Select(t => MangleClrTypeName(t))));
  488. }
  489. }
  490. }
  491. }