internal virtual void CreateFromStream(BinaryReader reader, Hashtable loggingTypeCache) { LoggingEventType id = (LoggingEventType)reader.ReadByte(); if (LoggingEventType.CustomEvent != id) { e = GetBuildEventArgFromId(id); if (!loggingTypeCache.Contains(id)) { Type eventType = e.GetType(); MethodInfo methodInfo = eventType.GetMethod("CreateFromStream", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod); loggingTypeCache.Add(id, methodInfo); } int packetVersion = (Environment.Version.Major * 10) + Environment.Version.Minor; ((MethodInfo)loggingTypeCache[id]).Invoke(e, new object[] { reader, packetVersion }); } else { string fileLocation = reader.ReadString(); bool resolveAssembly = false; lock (lockObject) { if (customEventsLoaded == null) { customEventsLoaded = new Hashtable(StringComparer.OrdinalIgnoreCase); resolveAssembly = true; } else { if (!customEventsLoaded.Contains(fileLocation)) { resolveAssembly = true; } } // If we are to resolve the assembly add it to the list of assemblies resolved if (resolveAssembly) { customEventsLoaded.Add(fileLocation, null); } } if (resolveAssembly) { resolver = new TaskEngineAssemblyResolver(); resolver.InstallHandler(); resolver.Initialize(fileLocation); } try { e = (BuildEventArgs)binaryFormatter.Deserialize(reader.BaseStream); } finally { if (resolveAssembly) { resolver.RemoveHandler(); resolver = null; } } } }
/// <summary> /// Sets up an app domain for the task batch, if necessary /// </summary> private AppDomain PrepareAppDomain() { // If the task assembly is loaded into a separate AppDomain using LoadFrom, then we have a problem // to solve - when the task class Type is marshalled back into our AppDomain, it's not just transferred // here. Instead, NDP will try to Load (not LoadFrom!) the task assembly into our AppDomain, and since // we originally used LoadFrom, it will fail miserably not knowing where to find it. // We need to temporarily subscribe to the AppDomain.AssemblyResolve event to fix it. if (null == resolver) { resolver = new TaskEngineAssemblyResolver(); resolver.Initialize(TaskClass.Assembly.AssemblyFile); resolver.InstallHandler(); } bool hasLoadInSeparateAppDomainAttribute = false; try { hasLoadInSeparateAppDomainAttribute = TaskClass.HasLoadInSeparateAppDomainAttribute(); } catch (Exception e) // Catching Exception, but rethrowing unless it's a well-known exception. { if (ExceptionHandling.NotExpectedReflectionException(e)) throw; // Reflection related exception ProjectErrorUtilities.VerifyThrowInvalidProject(false, taskNode, "TaskInstantiationFailureError", TaskName, TaskClass.Assembly.ToString(), e.Message); } AppDomain taskAppDomain = null; if (hasLoadInSeparateAppDomainAttribute) { if (!TaskClass.Type.IsMarshalByRef) { ProjectErrorUtilities.VerifyThrowInvalidProject(false, taskNode, "TaskNotMarshalByRef", TaskName); } else { // Our task depend on this name to be precisely that, so if you change it make sure // you also change the checks in the tasks run in separate AppDomains. Better yet, just don't change it. // Make sure we copy the appdomain configuration and send it to the appdomain we create so that if the creator of the current appdomain // has done the binding redirection in code, that we will get those settings as well. AppDomainSetup appDomainInfo = new AppDomainSetup(); // Get the current app domain setup settings byte[] currentAppdomainBytes = AppDomain.CurrentDomain.SetupInformation.GetConfigurationBytes(); //Apply the appdomain settings to the new appdomain before creating it appDomainInfo.SetConfigurationBytes(currentAppdomainBytes); taskAppDomain = AppDomain.CreateDomain("taskAppDomain", null, appDomainInfo); } } return taskAppDomain; }