internal InspectionResults Inspect(PipelineComponentType componentType, string assemblyFileName, string pipelineRootDirectory) { System.Diagnostics.Contracts.Contract.Requires(assemblyFileName != null); System.Diagnostics.Contracts.Contract.Requires(pipelineRootDirectory != null); _assemblyFileName = assemblyFileName; _pipelineRootDirectory = pipelineRootDirectory; // Set up the assembly resolve event. _currentComponentType = componentType; ResolveEventHandler assemblyResolver = new ResolveEventHandler(ResolveAssembly); AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += assemblyResolver; InspectionResults retval = new InspectionResults(); retval.Components = new List<PipelineComponent>(); retval.Warnings = new Collection<String>(); Type[] publicTypes; String assemblyName = null; // Need to assert again here because we are in a new appdomain FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, _pipelineRootDirectory); permission.Assert(); try { // We want to load the assembly WITHOUT REGARD OF PUBLISHER POLICY. // If the directory structure contains v1.0 of a component and v1.1 // exists in the GAC and is a security fix to v1.0, we still want to // inspect v1.0. (The reason is we have other parts of the // pipeline that were likely compiled against v1.0, not v1.1, and // we do type comparisons by comparing the fully qualified assembly // name.) LoadFrom unfortunately respects policy. Assembly's // ReflectionOnlyLoad(byte[]) doesn't. ReflectionOnlyLoadFrom(String) // does respect policy if you've set DEVPATH, but only as a bug. // We don't think setting DEVPATH is interesting. Assembly a = Assembly.ReflectionOnlyLoadFrom(_assemblyFileName); publicTypes = a.GetTypes(); assemblyName = a.FullName; } catch (FileNotFoundException fnf) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.AssemblyLoadFileNotFound, fnf.Message, fnf.FileName)); return retval; } catch (Exception e) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.AssemblyLoadThrew, e.GetType().Name, e.Message, _assemblyFileName)); return retval; } PipelineComponent component = null; String relativeFileName = Utils.MakeRelativePath(_assemblyFileName, _pipelineRootDirectory); Type lastType = null; try { // Iterate over public types, looking for the appropriate custom attributes. foreach (Type type in publicTypes) { component = null; lastType = type; switch (componentType) { case PipelineComponentType.Contract: if (!Utils.HasCustomAttribute(PipelineComponent.ContractAttributeInReflectionLoaderContext, type)) continue; component = new ContractComponent(new TypeInfo(type), relativeFileName); break; case PipelineComponentType.AddInAdapter: if (!Utils.HasCustomAttribute(PipelineComponent.AddInAdapterAttributeInReflectionLoaderContext, type)) continue; component = new AddInAdapter(new TypeInfo(type), relativeFileName); break; case PipelineComponentType.AddInBase: if (Utils.HasCustomAttribute(PipelineComponent.AddInAttributeInReflectionLoaderContext, type)) retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.AddInInAddInViewFolder, type.Name, _assemblyFileName)); if (!Utils.HasCustomAttribute(PipelineComponent.AddInBaseAttributeInReflectionLoaderContext, type)) continue; TypeInfo[] activatableAs = null; CustomAttributeData cad = Utils.GetCustomAttributeData(PipelineComponent.AddInBaseAttributeInReflectionLoaderContext, type); foreach(CustomAttributeNamedArgument cana in cad.NamedArguments) { if (cana.MemberInfo.Name == "ActivatableAs") { CustomAttributeTypedArgument arg = cana.TypedValue; ReadOnlyCollection<CustomAttributeTypedArgument> types = (ReadOnlyCollection<CustomAttributeTypedArgument>)arg.Value; activatableAs = new TypeInfo[types.Count]; int i = 0; foreach (CustomAttributeTypedArgument subArg in types) { activatableAs[i++] = new TypeInfo((Type)subArg.Value); } } } component = new AddInBase(new TypeInfo(type), activatableAs, relativeFileName, assemblyName); break; default: System.Diagnostics.Contracts.Contract.Assert(false, "Fell through switch - unrecognized componentType in InspectionWorker.Inspect"); break; } // switch // If we found a component, make sure it satisfies all of its constraints, and give our // PipelineComponents a chance to initialize state. if (component != null) { if (component.Validate(type, retval.Warnings)) retval.Components.Add(component); } } // foreach type in the assembly } // try catch (FileNotFoundException fnf) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.AssemblyLoadFileNotFound, fnf.Message, fnf.FileName)); return retval; } catch (NotImplementedException) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.NotImplementedFeatureBadCtorParamOrAssembly, _assemblyFileName, (lastType == null) ? "" : lastType.FullName)); return retval; } catch (Exception e) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.InspectingAssemblyThrew, e.GetType().Name, e.Message, _assemblyFileName)); return retval; } AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= assemblyResolver; if (retval.Components.Count == 0 && _currentComponentType != PipelineComponentType.AddIn && _currentComponentType != PipelineComponentType.AddInBase) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.NoAddInModelPartsFound, componentType, _assemblyFileName)); } #if ADDIN_VERBOSE_WARNINGS foreach (PipelineComponent c in retval.Components) retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, "Found a {0}. Name: {1} Assembly: {2}", componentType, c.SimpleName, c.AssemblySimpleName)); #endif return retval; }
internal InspectionResults Inspect(PipelineComponentType componentType, string assemblyFileName, string pipelineRootDirectory) { System.Diagnostics.Contracts.Contract.Requires(assemblyFileName != null); System.Diagnostics.Contracts.Contract.Requires(pipelineRootDirectory != null); _assemblyFileName = assemblyFileName; _pipelineRootDirectory = pipelineRootDirectory; // Set up the assembly resolve event. _currentComponentType = componentType; ResolveEventHandler assemblyResolver = new ResolveEventHandler(ResolveAssembly); AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += assemblyResolver; InspectionResults retval = new InspectionResults(); retval.Components = new List <PipelineComponent>(); retval.Warnings = new Collection <String>(); Type[] publicTypes; String assemblyName = null; // Need to assert again here because we are in a new appdomain FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, _pipelineRootDirectory); permission.Assert(); try { // We want to load the assembly WITHOUT REGARD OF PUBLISHER POLICY. // If the directory structure contains v1.0 of a component and v1.1 // exists in the GAC and is a security fix to v1.0, we still want to // inspect v1.0. (The reason is we have other parts of the // pipeline that were likely compiled against v1.0, not v1.1, and // we do type comparisons by comparing the fully qualified assembly // name.) LoadFrom unfortunately respects policy. Assembly's // ReflectionOnlyLoad(byte[]) doesn't. ReflectionOnlyLoadFrom(String) // does respect policy if you've set DEVPATH, but only as a bug. // We don't think setting DEVPATH is interesting. Assembly a = Assembly.ReflectionOnlyLoadFrom(_assemblyFileName); publicTypes = a.GetTypes(); assemblyName = a.FullName; } catch (FileNotFoundException fnf) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.AssemblyLoadFileNotFound, fnf.Message, fnf.FileName)); return(retval); } catch (Exception e) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.AssemblyLoadThrew, e.GetType().Name, e.Message, _assemblyFileName)); return(retval); } PipelineComponent component = null; String relativeFileName = Utils.MakeRelativePath(_assemblyFileName, _pipelineRootDirectory); Type lastType = null; try { // Iterate over public types, looking for the appropriate custom attributes. foreach (Type type in publicTypes) { component = null; lastType = type; switch (componentType) { case PipelineComponentType.Contract: if (!Utils.HasCustomAttribute(PipelineComponent.ContractAttributeInReflectionLoaderContext, type)) { continue; } component = new ContractComponent(new TypeInfo(type), relativeFileName); break; case PipelineComponentType.AddInAdapter: if (!Utils.HasCustomAttribute(PipelineComponent.AddInAdapterAttributeInReflectionLoaderContext, type)) { continue; } component = new AddInAdapter(new TypeInfo(type), relativeFileName); break; case PipelineComponentType.AddInBase: if (Utils.HasCustomAttribute(PipelineComponent.AddInAttributeInReflectionLoaderContext, type)) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.AddInInAddInViewFolder, type.Name, _assemblyFileName)); } if (!Utils.HasCustomAttribute(PipelineComponent.AddInBaseAttributeInReflectionLoaderContext, type)) { continue; } TypeInfo[] activatableAs = null; CustomAttributeData cad = Utils.GetCustomAttributeData(PipelineComponent.AddInBaseAttributeInReflectionLoaderContext, type); foreach (CustomAttributeNamedArgument cana in cad.NamedArguments) { if (cana.MemberInfo.Name == "ActivatableAs") { CustomAttributeTypedArgument arg = cana.TypedValue; ReadOnlyCollection <CustomAttributeTypedArgument> types = (ReadOnlyCollection <CustomAttributeTypedArgument>)arg.Value; activatableAs = new TypeInfo[types.Count]; int i = 0; foreach (CustomAttributeTypedArgument subArg in types) { activatableAs[i++] = new TypeInfo((Type)subArg.Value); } } } component = new AddInBase(new TypeInfo(type), activatableAs, relativeFileName, assemblyName); break; default: System.Diagnostics.Contracts.Contract.Assert(false, "Fell through switch - unrecognized componentType in InspectionWorker.Inspect"); break; } // switch // If we found a component, make sure it satisfies all of its constraints, and give our // PipelineComponents a chance to initialize state. if (component != null) { if (component.Validate(type, retval.Warnings)) { retval.Components.Add(component); } } } // foreach type in the assembly } // try catch (FileNotFoundException fnf) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.AssemblyLoadFileNotFound, fnf.Message, fnf.FileName)); return(retval); } catch (NotImplementedException) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.NotImplementedFeatureBadCtorParamOrAssembly, _assemblyFileName, (lastType == null) ? "" : lastType.FullName)); return(retval); } catch (Exception e) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.InspectingAssemblyThrew, e.GetType().Name, e.Message, _assemblyFileName)); return(retval); } AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= assemblyResolver; if (retval.Components.Count == 0 && _currentComponentType != PipelineComponentType.AddIn && _currentComponentType != PipelineComponentType.AddInBase) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.NoAddInModelPartsFound, componentType, _assemblyFileName)); } #if ADDIN_VERBOSE_WARNINGS foreach (PipelineComponent c in retval.Components) { retval.Warnings.Add(String.Format(CultureInfo.CurrentCulture, "Found a {0}. Name: {1} Assembly: {2}", componentType, c.SimpleName, c.AssemblySimpleName)); } #endif return(retval); }