1 // -----------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 // -----------------------------------------------------------------------
5 using System.Collections.Generic;
6 using System.Diagnostics.CodeAnalysis;
7 using System.Globalization;
8 using System.Reflection;
9 using Microsoft.Internal;
11 namespace System.ComponentModel.Composition
13 internal static class MetadataViewProvider
15 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
16 public static TMetadataView GetMetadataView<TMetadataView>(IDictionary<string, object> metadata)
18 Assumes.NotNull(metadata);
20 Type metadataViewType = typeof(TMetadataView);
22 // If the Metadata dictionary is cast compatible with the passed in type
23 if (metadataViewType.IsAssignableFrom(typeof(IDictionary<string, object>)))
25 return (TMetadataView)metadata;
27 // otherwise is it a metadata view
31 if (metadataViewType.IsInterface)
33 if(!metadataViewType.IsAttributeDefined<MetadataViewImplementationAttribute>())
38 proxyType = MetadataViewGenerator.GenerateView(metadataViewType);
40 catch (TypeLoadException ex)
42 throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.NotSupportedInterfaceMetadataView, metadataViewType.FullName), ex);
45 throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.NotSupportedInterfaceMetadataView, metadataViewType.FullName));
50 var implementationAttribute = metadataViewType.GetFirstAttribute<MetadataViewImplementationAttribute>();
51 proxyType = implementationAttribute.ImplementationType;
54 throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture,
55 Strings.ContractMismatch_MetadataViewImplementationCanNotBeNull,
56 metadataViewType.FullName,
61 if(!metadataViewType.IsAssignableFrom(proxyType))
63 throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture,
64 Strings.ContractMismatch_MetadataViewImplementationDoesNotImplementViewInterface,
65 metadataViewType.FullName,
73 proxyType = metadataViewType;
76 // Now we have the type for the proxy create it
79 return (TMetadataView)proxyType.SafeCreateInstance(metadata);
81 catch (MissingMethodException ex)
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);
88 catch (TargetInvocationException ex)
91 //Unwrap known failures that we want to present as CompositionContractMismatchException
92 if(metadataViewType.IsInterface)
94 if(ex.InnerException.GetType() == typeof(InvalidCastException))
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);
105 else if (ex.InnerException.GetType() == typeof(NullReferenceException))
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);
121 public static bool IsViewTypeValid(Type metadataViewType)
123 Assumes.NotNull(metadataViewType);
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))