Merge pull request #799 from kebby/master
[mono.git] / mcs / class / System.ComponentModel.Composition.4.5 / src / ComponentModel / System / ComponentModel / Composition / MetadataViewProvider.cs
1 // -----------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 // -----------------------------------------------------------------------
4 using System;
5 using System.Collections.Generic;
6 using System.Diagnostics.CodeAnalysis;
7 using System.Globalization;
8 using System.Reflection;
9 using Microsoft.Internal;
10
11 namespace System.ComponentModel.Composition
12 {
13     internal static class MetadataViewProvider
14     {
15         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
16         public static TMetadataView GetMetadataView<TMetadataView>(IDictionary<string, object> metadata)
17         {
18             Assumes.NotNull(metadata);
19
20             Type metadataViewType = typeof(TMetadataView);
21
22             // If the Metadata dictionary is cast compatible with the passed in type
23             if (metadataViewType.IsAssignableFrom(typeof(IDictionary<string, object>)))
24             {
25                 return (TMetadataView)metadata;
26             }
27             // otherwise is it a metadata view
28             else
29             {
30                 Type proxyType;
31                 if (metadataViewType.IsInterface)
32                 {
33                     if(!metadataViewType.IsAttributeDefined<MetadataViewImplementationAttribute>())
34                     {
35 #if !FULL_AOT_RUNTIME
36                         try
37                         {
38                             proxyType = MetadataViewGenerator.GenerateView(metadataViewType);
39                         }
40                         catch (TypeLoadException ex)
41                         {
42                             throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.NotSupportedInterfaceMetadataView, metadataViewType.FullName), ex);
43                         }
44 #else
45                         throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.NotSupportedInterfaceMetadataView, metadataViewType.FullName));
46 #endif
47                     }
48                     else
49                     {
50                         var implementationAttribute = metadataViewType.GetFirstAttribute<MetadataViewImplementationAttribute>();
51                         proxyType = implementationAttribute.ImplementationType;
52                         if(proxyType == null)
53                         {
54                             throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture, 
55                                 Strings.ContractMismatch_MetadataViewImplementationCanNotBeNull,
56                                 metadataViewType.FullName,
57                                 proxyType.FullName));
58                         }
59                         else
60                         {
61                             if(!metadataViewType.IsAssignableFrom(proxyType))
62                             {
63                                 throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture, 
64                                     Strings.ContractMismatch_MetadataViewImplementationDoesNotImplementViewInterface,
65                                     metadataViewType.FullName,
66                                     proxyType.FullName));
67                             }
68                         }
69                     }
70                 }
71                 else
72                 {
73                     proxyType = metadataViewType;
74                 }
75
76                 // Now we have the type for the proxy create it
77                 try
78                 {
79                     return (TMetadataView)proxyType.SafeCreateInstance(metadata);
80                 }
81                 catch (MissingMethodException ex)
82                 {
83                     // Unable to create an Instance of the Metadata view '{0}' because a constructor could not be selected.  Ensure that the type implements a constructor which takes an argument of type IDictionary<string, object>.
84                     throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture,
85                         Strings.CompositionException_MetadataViewInvalidConstructor,
86                         proxyType.AssemblyQualifiedName), ex);
87                 }
88                 catch (TargetInvocationException ex)
89                 {
90 #if !FULL_AOT_RUNTIME
91                     //Unwrap known failures that we want to present as CompositionContractMismatchException
92                     if(metadataViewType.IsInterface)
93                     {
94                         if(ex.InnerException.GetType() == typeof(InvalidCastException))
95                         {
96                             // Unable to create an Instance of the Metadata view {0} because the exporter exported the metadata for the item {1} with the value {2} as type {3} but the view imports it as type {4}.
97                             throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture, 
98                                 Strings.ContractMismatch_InvalidCastOnMetadataField,
99                                 ex.InnerException.Data[MetadataViewGenerator.MetadataViewType],
100                                 ex.InnerException.Data[MetadataViewGenerator.MetadataItemKey],
101                                 ex.InnerException.Data[MetadataViewGenerator.MetadataItemValue],
102                                 ex.InnerException.Data[MetadataViewGenerator.MetadataItemSourceType],
103                                 ex.InnerException.Data[MetadataViewGenerator.MetadataItemTargetType]), ex);
104                         }
105                         else if (ex.InnerException.GetType() == typeof(NullReferenceException))
106                         {
107                             // Unable to create an Instance of the Metadata view {0} because the exporter exported the metadata for the item {1} with a null value and null is not a valid value for type {2}.
108                             throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture,
109                                 Strings.ContractMismatch_NullReferenceOnMetadataField,
110                                 ex.InnerException.Data[MetadataViewGenerator.MetadataViewType],
111                                 ex.InnerException.Data[MetadataViewGenerator.MetadataItemKey],
112                                 ex.InnerException.Data[MetadataViewGenerator.MetadataItemTargetType]), ex);
113                         }
114                     }
115 #endif
116                     throw;
117                 }
118             }
119         }
120
121         public static bool IsViewTypeValid(Type metadataViewType)
122         {
123             Assumes.NotNull(metadataViewType);
124
125             // If the Metadata dictionary is cast compatible with the passed in type
126             if (ExportServices.IsDefaultMetadataViewType(metadataViewType)
127             ||  metadataViewType.IsInterface
128             ||  ExportServices.IsDictionaryConstructorViewType(metadataViewType))
129             {
130                 return true;
131             }
132
133             return false;
134         }
135     }
136 }