internal PartialToken(HostAdapter hostAdapter, ContractComponent contract, AddInAdapter addinAdapter, AddInBase addinBase) { System.Diagnostics.Contracts.Contract.Requires(hostAdapter != null); System.Diagnostics.Contracts.Contract.Requires(contract != null); System.Diagnostics.Contracts.Contract.Requires(addinAdapter != null); System.Diagnostics.Contracts.Contract.Requires(addinBase != null); _hostAdapter = hostAdapter; _contract = contract; _addinAdapter = addinAdapter; _addinBase = addinBase; }
internal AddInToken(HostAdapter hostAdapter, ContractComponent contract, AddInAdapter addinAdapter, AddInBase addinBase, AddIn addin) { System.Diagnostics.Contracts.Contract.Requires(hostAdapter != null); System.Diagnostics.Contracts.Contract.Requires(contract != null); System.Diagnostics.Contracts.Contract.Requires(addinAdapter != null); System.Diagnostics.Contracts.Contract.Requires(addinBase != null); System.Diagnostics.Contracts.Contract.Requires(addin != null); _hostAddinViews = hostAdapter.HostAddinViews; _hostAdapter = hostAdapter; _contract = contract; _addinAdapter = addinAdapter; _addinBase = addinBase; _addin = addin; // _pipelineRootDir must be filled in after deserialization. }
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); }
// Detects two somewhat easy to hit user bugs, where the contract assembly // is loaded twice in different loader contexts, or where the add-in adapter // has been loaded in the host's assembly. If either of these happens, // then the transparent proxy will not be castable to the interface type, // and the remoting code will attempt to load the addin adapter's // type in the host's appdomain. // We explicitly do not allow the add-in adapter's assembly to leak // into this appdomain. If the contract assembly exists in the same // directory as the application, or in potentially other locations, it may // get loaded twice in different loader contexts by the CLR V2's loader. // This took about a week to debug, with experts from all the affected areas. private static void CheckForLoaderContextProblems(ContractComponent contract, AddInAdapter addinAdapter, Exception inner) { String contractAsmName = contract.TypeInfo.AssemblyName; String addinAdapterAsmName = addinAdapter.TypeInfo.AssemblyName; List <Assembly> contracts = new List <Assembly>(); List <Assembly> addinAdapters = new List <Assembly>(); foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { String aName = a.GetName().FullName; if (aName == contractAsmName) { contracts.Add(a); } if (aName == addinAdapterAsmName) { addinAdapters.Add(a); } } if (addinAdapters.Count > 0) { StringBuilder locations = new StringBuilder(); foreach (Assembly a in addinAdapters) { locations.Append(Environment.NewLine); locations.Append(a.CodeBase); } Exception e = new InvalidOperationException( String.Format(CultureInfo.CurrentCulture, Res.AddInAdapterLoadedInWrongAppDomain, addinAdapter.TypeInfo.AssemblyName, addinAdapter.Location, locations.ToString()), inner); e.Data["Incorrectly loaded add-in adapters"] = addinAdapters; e.Data["Expected adapter location"] = addinAdapter.Location; if (contracts.Count > 1) { e.Data["Duplicate Contracts"] = contracts; } throw e; } if (contracts.Count > 1) { StringBuilder locations = new StringBuilder(); foreach (Assembly a in contracts) { locations.Append(Environment.NewLine); locations.Append(a.CodeBase); } Exception e = new InvalidOperationException( String.Format(CultureInfo.CurrentCulture, Res.ContractAssemblyLoadedMultipleTimes, contract.TypeInfo.AssemblyName, contract.Location, locations.ToString()), inner); e.Data["Incorrectly loaded contracts"] = contracts; e.Data["Expected contract location"] = contract.Location; throw e; } else { // If you're seeing this in a debugger on V2 of the CLR, make sure you hook the assembly resolve event. // Otherwise, see if there was an ArgumentException thrown from an HAV's constructor. System.Diagnostics.Contracts.Contract.Assert(false, "Did the AddIn Model upgrade the contract to the default loader context using an assembly resolve event? Either that, or your HAV's constructor threw an ArgumentException"); } }