//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // Microsoft //------------------------------------------------------------------------------ namespace System.Xml.Serialization { using System.Configuration; using System.Reflection; using System.Reflection.Emit; using System.Collections; using System.IO; using System; using System.Text; using System.Xml; using System.Threading; using System.Security; using System.Security.Permissions; using System.Security.Policy; using System.Xml.Serialization.Configuration; using System.Diagnostics; using System.CodeDom.Compiler; using System.Globalization; using System.Runtime.Versioning; using System.Diagnostics.CodeAnalysis; internal class TempAssembly { internal const string GeneratedAssemblyNamespace = "Microsoft.Xml.Serialization.GeneratedAssembly"; Assembly assembly; bool pregeneratedAssmbly = false; XmlSerializerImplementation contract = null; Hashtable writerMethods; Hashtable readerMethods; TempMethodDictionary methods; static object[] emptyObjectArray = new object[0]; Hashtable assemblies = new Hashtable(); static volatile FileIOPermission fileIOPermission; internal class TempMethod { internal MethodInfo writeMethod; internal MethodInfo readMethod; internal string name; internal string ns; internal bool isSoap; internal string methodKey; } private TempAssembly() { } internal TempAssembly(XmlMapping[] xmlMappings, Type[] types, string defaultNamespace, string location, Evidence evidence) { bool containsSoapMapping = false; for (int i = 0; i < xmlMappings.Length; i++) { xmlMappings[i].CheckShallow(); if (xmlMappings[i].IsSoap) { containsSoapMapping = true; } } // We will make best effort to use RefEmit for assembly generation bool fallbackToCSharpAssemblyGeneration = false; if (!containsSoapMapping && !TempAssembly.UseLegacySerializerGeneration) { try { assembly = GenerateRefEmitAssembly(xmlMappings, types, defaultNamespace, evidence); } // Only catch and handle known failures with RefEmit catch (CodeGeneratorConversionException) { fallbackToCSharpAssemblyGeneration = true; } // Add other known exceptions here... // } else { fallbackToCSharpAssemblyGeneration = true; } if (fallbackToCSharpAssemblyGeneration) { assembly = GenerateAssembly(xmlMappings, types, defaultNamespace, evidence, XmlSerializerCompilerParameters.Create(location), null, assemblies); } #if DEBUG // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe if (assembly == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Failed to generate XmlSerializer assembly, but did not throw")); #endif InitAssemblyMethods(xmlMappings); } internal TempAssembly(XmlMapping[] xmlMappings, Assembly assembly, XmlSerializerImplementation contract) { this.assembly = assembly; InitAssemblyMethods(xmlMappings); this.contract = contract; pregeneratedAssmbly = true; } internal static bool UseLegacySerializerGeneration { get { if (AppSettings.UseLegacySerializerGeneration.HasValue) { // AppSetting will always win if specified return (bool) AppSettings.UseLegacySerializerGeneration; } else { #if CONFIGURATION_DEP XmlSerializerSection configSection = ConfigurationManager.GetSection(ConfigurationStrings.XmlSerializerSectionPath) as XmlSerializerSection; return configSection == null ? false : configSection.UseLegacySerializerGeneration; #else return false; #endif } } } internal TempAssembly(XmlSerializerImplementation contract) { this.contract = contract; pregeneratedAssmbly = true; } internal XmlSerializerImplementation Contract { get { if (contract == null) { contract = (XmlSerializerImplementation)Activator.CreateInstance(GetTypeFromAssembly(this.assembly, "XmlSerializerContract")); } return contract; } } internal void InitAssemblyMethods(XmlMapping[] xmlMappings) { methods = new TempMethodDictionary(); for (int i = 0; i < xmlMappings.Length; i++) { TempMethod method = new TempMethod(); method.isSoap = xmlMappings[i].IsSoap; method.methodKey = xmlMappings[i].Key; XmlTypeMapping xmlTypeMapping = xmlMappings[i] as XmlTypeMapping; if (xmlTypeMapping != null) { method.name = xmlTypeMapping.ElementName; method.ns = xmlTypeMapping.Namespace; } methods.Add(xmlMappings[i].Key, method); } } /// /// /// Attempts to load pre-generated serialization assembly. /// First check for the [XmlSerializerAssembly] attribute /// /// // SxS: This method does not take any resource name and does not expose any resources to the caller. // It's OK to suppress the SxS warning. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [ResourceExposure(ResourceScope.None)] internal static Assembly LoadGeneratedAssembly(Type type, string defaultNamespace, out XmlSerializerImplementation contract) { Assembly serializer = null; contract = null; string serializerName = null; // Packaged apps do not support loading generated serializers. if (Microsoft.Win32.UnsafeNativeMethods.IsPackagedProcess.Value) { return null; } bool logEnabled = DiagnosticsSwitches.PregenEventLog.Enabled; // check to see if we loading explicit pre-generated assembly object[] attrs = type.GetCustomAttributes(typeof(XmlSerializerAssemblyAttribute), false); if (attrs.Length == 0) { // Guess serializer name: if parent assembly signed use strong name AssemblyName name = GetName(type.Assembly, true); serializerName = Compiler.GetTempAssemblyName(name, defaultNamespace); // use strong name name.Name = serializerName; name.CodeBase = null; name.CultureInfo = CultureInfo.InvariantCulture; try { serializer = Assembly.Load(name); } catch (Exception e) { if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) { throw; } if (logEnabled) { Log(e.Message, EventLogEntryType.Information); } byte[] token = name.GetPublicKeyToken(); if (token != null && token.Length > 0) { // the parent assembly was signed, so do not try to LoadWithPartialName return null; } #pragma warning disable 618 serializer = Assembly.LoadWithPartialName(serializerName, null); #pragma warning restore 618 } if (serializer == null) { #if !FEATURE_PAL // EventLog if (logEnabled) { Log(Res.GetString(Res.XmlPregenCannotLoad, serializerName), EventLogEntryType.Information); } #endif //!FEATURE_PAL // EventLog return null; } if (!IsSerializerVersionMatch(serializer, type, defaultNamespace, null)) { #if !FEATURE_PAL // EventLog if (logEnabled) Log(Res.GetString(Res.XmlSerializerExpiredDetails, serializerName, type.FullName), EventLogEntryType.Error); #endif //!FEATURE_PAL // EventLog return null; } } else { XmlSerializerAssemblyAttribute assemblyAttribute = (XmlSerializerAssemblyAttribute)attrs[0]; if (assemblyAttribute.AssemblyName != null && assemblyAttribute.CodeBase != null) throw new InvalidOperationException(Res.GetString(Res.XmlPregenInvalidXmlSerializerAssemblyAttribute, "AssemblyName", "CodeBase")); // found XmlSerializerAssemblyAttribute attribute, it should have all needed information to load the pre-generated serializer if (assemblyAttribute.AssemblyName != null) { serializerName = assemblyAttribute.AssemblyName; #pragma warning disable 618 serializer = Assembly.LoadWithPartialName(serializerName, null); #pragma warning restore 618 } else if (assemblyAttribute.CodeBase != null && assemblyAttribute.CodeBase.Length > 0) { serializerName = assemblyAttribute.CodeBase; serializer = Assembly.LoadFrom(serializerName); } else { serializerName = type.Assembly.FullName; serializer = type.Assembly; } if (serializer == null) { throw new FileNotFoundException(null, serializerName); } } Type contractType = GetTypeFromAssembly(serializer, "XmlSerializerContract"); contract = (XmlSerializerImplementation)Activator.CreateInstance(contractType); if (contract.CanSerialize(type)) return serializer; #if !FEATURE_PAL // EventLog if (logEnabled) Log(Res.GetString(Res.XmlSerializerExpiredDetails, serializerName, type.FullName), EventLogEntryType.Error); #endif //!FEATURE_PAL // EventLog return null; } #if !FEATURE_PAL // EventLog static void Log(string message, EventLogEntryType type) { new EventLogPermission(PermissionState.Unrestricted).Assert(); EventLog.WriteEntry("XmlSerializer", message, type); } #endif //!FEATURE_PAL // EventLog static AssemblyName GetName(Assembly assembly, bool copyName) { PermissionSet perms = new PermissionSet(PermissionState.None); perms.AddPermission(new FileIOPermission(PermissionState.Unrestricted)); perms.Assert(); return assembly.GetName(copyName); } static bool IsSerializerVersionMatch(Assembly serializer, Type type, string defaultNamespace, string location) { if (serializer == null) return false; object[] attrs = serializer.GetCustomAttributes(typeof(XmlSerializerVersionAttribute), false); if (attrs.Length != 1) return false; XmlSerializerVersionAttribute assemblyInfo = (XmlSerializerVersionAttribute)attrs[0]; // we found out dated pre-generate assembly // if (assemblyInfo.ParentAssemblyId == GenerateAssemblyId(type) && assemblyInfo.Namespace == defaultNamespace) return true; return false; } // SxS: This method does not take any resource name and does not expose any resources to the caller. // It's OK to suppress the SxS warning. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [ResourceExposure(ResourceScope.None)] static string GenerateAssemblyId(Type type) { Module[] modules = type.Assembly.GetModules(); ArrayList list = new ArrayList(); for (int i = 0; i < modules.Length; i++) { list.Add(modules[i].ModuleVersionId.ToString()); } list.Sort(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < list.Count; i++) { sb.Append(list[i].ToString()); sb.Append(","); } return sb.ToString(); } internal static Assembly GenerateAssembly(XmlMapping[] xmlMappings, Type[] types, string defaultNamespace, Evidence evidence, XmlSerializerCompilerParameters parameters, Assembly assembly, Hashtable assemblies) { FileIOPermission.Assert(); Compiler compiler = new Compiler(); try { Hashtable scopeTable = new Hashtable(); foreach (XmlMapping mapping in xmlMappings) scopeTable[mapping.Scope] = mapping; TypeScope[] scopes = new TypeScope[scopeTable.Keys.Count]; scopeTable.Keys.CopyTo(scopes, 0); assemblies.Clear(); Hashtable importedTypes = new Hashtable(); foreach (TypeScope scope in scopes) { foreach (Type t in scope.Types) { compiler.AddImport(t, importedTypes); Assembly a = t.Assembly; string name = a.FullName; if (assemblies[name] != null) continue; if (!a.GlobalAssemblyCache) { assemblies[name] = a; } } } for (int i = 0; i < types.Length; i++) { compiler.AddImport(types[i], importedTypes); } compiler.AddImport(typeof(object).Assembly); compiler.AddImport(typeof(XmlSerializer).Assembly); IndentedWriter writer = new IndentedWriter(compiler.Source, false); writer.WriteLine("#if _DYNAMIC_XMLSERIALIZER_COMPILATION"); writer.WriteLine("[assembly:System.Security.AllowPartiallyTrustedCallers()]"); writer.WriteLine("[assembly:System.Security.SecurityTransparent()]"); writer.WriteLine("[assembly:System.Security.SecurityRules(System.Security.SecurityRuleSet.Level1)]"); writer.WriteLine("#endif"); // Add AssemblyVersion attribute to match parent accembly version if (types != null && types.Length > 0 && types[0] != null) { writer.WriteLine("[assembly:System.Reflection.AssemblyVersionAttribute(\"" + types[0].Assembly.GetName().Version.ToString() + "\")]"); } if (assembly != null && types.Length > 0) { for (int i = 0; i < types.Length; i++) { Type type = types[i]; if (type == null) continue; if (DynamicAssemblies.IsTypeDynamic(type)) { throw new InvalidOperationException(Res.GetString(Res.XmlPregenTypeDynamic, types[i].FullName)); } } writer.Write("[assembly:"); writer.Write(typeof(XmlSerializerVersionAttribute).FullName); writer.Write("("); writer.Write("ParentAssemblyId="); ReflectionAwareCodeGen.WriteQuotedCSharpString(writer, GenerateAssemblyId(types[0])); writer.Write(", Version="); ReflectionAwareCodeGen.WriteQuotedCSharpString(writer, ThisAssembly.Version); if (defaultNamespace != null) { writer.Write(", Namespace="); ReflectionAwareCodeGen.WriteQuotedCSharpString(writer, defaultNamespace); } writer.WriteLine(")]"); } CodeIdentifiers classes = new CodeIdentifiers(); classes.AddUnique("XmlSerializationWriter", "XmlSerializationWriter"); classes.AddUnique("XmlSerializationReader", "XmlSerializationReader"); string suffix = null; if (types != null && types.Length == 1 && types[0] != null) { suffix = CodeIdentifier.MakeValid(types[0].Name); if (types[0].IsArray) { suffix += "Array"; } } writer.WriteLine("namespace " + GeneratedAssemblyNamespace + " {"); writer.Indent++; writer.WriteLine(); string writerClass = "XmlSerializationWriter" + suffix; writerClass = classes.AddUnique(writerClass, writerClass); XmlSerializationWriterCodeGen writerCodeGen = new XmlSerializationWriterCodeGen(writer, scopes, "public", writerClass); writerCodeGen.GenerateBegin(); string[] writeMethodNames = new string[xmlMappings.Length]; for (int i = 0; i < xmlMappings.Length; i++) { writeMethodNames[i] = writerCodeGen.GenerateElement(xmlMappings[i]); } writerCodeGen.GenerateEnd(); writer.WriteLine(); string readerClass = "XmlSerializationReader" + suffix; readerClass = classes.AddUnique(readerClass, readerClass); XmlSerializationReaderCodeGen readerCodeGen = new XmlSerializationReaderCodeGen(writer, scopes, "public", readerClass); readerCodeGen.GenerateBegin(); string[] readMethodNames = new string[xmlMappings.Length]; for (int i = 0; i < xmlMappings.Length; i++) { readMethodNames[i] = readerCodeGen.GenerateElement(xmlMappings[i]); } readerCodeGen.GenerateEnd(readMethodNames, xmlMappings, types); string baseSerializer = readerCodeGen.GenerateBaseSerializer("XmlSerializer1", readerClass, writerClass, classes); Hashtable serializers = new Hashtable(); for (int i = 0; i < xmlMappings.Length; i++) { if (serializers[xmlMappings[i].Key] == null) { serializers[xmlMappings[i].Key] = readerCodeGen.GenerateTypedSerializer(readMethodNames[i], writeMethodNames[i], xmlMappings[i], classes, baseSerializer, readerClass, writerClass); } } readerCodeGen.GenerateSerializerContract("XmlSerializerContract", xmlMappings, types, readerClass, readMethodNames, writerClass, writeMethodNames, serializers); writer.Indent--; writer.WriteLine("}"); return compiler.Compile(assembly, defaultNamespace, parameters, evidence); } finally { compiler.Close(); } } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification="It is safe because the serialization assembly is generated by the framework code, not by the user.")] internal static Assembly GenerateRefEmitAssembly(XmlMapping[] xmlMappings, Type[] types, string defaultNamespace, Evidence evidence) { Hashtable scopeTable = new Hashtable(); foreach (XmlMapping mapping in xmlMappings) scopeTable[mapping.Scope] = mapping; TypeScope[] scopes = new TypeScope[scopeTable.Keys.Count]; scopeTable.Keys.CopyTo(scopes, 0); string assemblyName = "Microsoft.GeneratedCode"; AssemblyBuilder assemblyBuilder = CodeGenerator.CreateAssemblyBuilder(AppDomain.CurrentDomain, assemblyName); ConstructorInfo SecurityTransparentAttribute_ctor = typeof(SecurityTransparentAttribute).GetConstructor( CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(SecurityTransparentAttribute_ctor, new Object[0])); ConstructorInfo AllowPartiallyTrustedCallersAttribute_ctor = typeof(AllowPartiallyTrustedCallersAttribute).GetConstructor( CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(AllowPartiallyTrustedCallersAttribute_ctor, new Object[0])); ConstructorInfo SecurityRulesAttribute_ctor = typeof(SecurityRulesAttribute).GetConstructor( CodeGenerator.InstanceBindingFlags, null, new Type[] { typeof(SecurityRuleSet) }, null ); assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(SecurityRulesAttribute_ctor, new Object[] { SecurityRuleSet.Level1 })); // Add AssemblyVersion attribute to match parent accembly version if (types != null && types.Length > 0 && types[0] != null) { ConstructorInfo AssemblyVersionAttribute_ctor = typeof(AssemblyVersionAttribute).GetConstructor( CodeGenerator.InstanceBindingFlags, null, new Type[] { typeof(String) }, null ); FileIOPermission.Assert(); string assemblyVersion = types[0].Assembly.GetName().Version.ToString(); FileIOPermission.RevertAssert(); assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(AssemblyVersionAttribute_ctor, new Object[] { assemblyVersion })); } CodeIdentifiers classes = new CodeIdentifiers(); classes.AddUnique("XmlSerializationWriter", "XmlSerializationWriter"); classes.AddUnique("XmlSerializationReader", "XmlSerializationReader"); string suffix = null; if (types != null && types.Length == 1 && types[0] != null) { suffix = CodeIdentifier.MakeValid(types[0].Name); if (types[0].IsArray) { suffix += "Array"; } } ModuleBuilder moduleBuilder = CodeGenerator.CreateModuleBuilder(assemblyBuilder, assemblyName); string writerClass = "XmlSerializationWriter" + suffix; writerClass = classes.AddUnique(writerClass, writerClass); XmlSerializationWriterILGen writerCodeGen = new XmlSerializationWriterILGen(scopes, "public", writerClass); writerCodeGen.ModuleBuilder = moduleBuilder; writerCodeGen.GenerateBegin(); string[] writeMethodNames = new string[xmlMappings.Length]; for (int i = 0; i < xmlMappings.Length; i++) { writeMethodNames[i] = writerCodeGen.GenerateElement(xmlMappings[i]); } Type writerType = writerCodeGen.GenerateEnd(); string readerClass = "XmlSerializationReader" + suffix; readerClass = classes.AddUnique(readerClass, readerClass); XmlSerializationReaderILGen readerCodeGen = new XmlSerializationReaderILGen(scopes, "public", readerClass); readerCodeGen.ModuleBuilder = moduleBuilder; readerCodeGen.CreatedTypes.Add(writerType.Name, writerType); readerCodeGen.GenerateBegin(); string[] readMethodNames = new string[xmlMappings.Length]; for (int i = 0; i < xmlMappings.Length; i++) { readMethodNames[i] = readerCodeGen.GenerateElement(xmlMappings[i]); } readerCodeGen.GenerateEnd(readMethodNames, xmlMappings, types); string baseSerializer = readerCodeGen.GenerateBaseSerializer("XmlSerializer1", readerClass, writerClass, classes); Hashtable serializers = new Hashtable(); for (int i = 0; i < xmlMappings.Length; i++) { if (serializers[xmlMappings[i].Key] == null) { serializers[xmlMappings[i].Key] = readerCodeGen.GenerateTypedSerializer(readMethodNames[i], writeMethodNames[i], xmlMappings[i], classes, baseSerializer, readerClass, writerClass); } } readerCodeGen.GenerateSerializerContract("XmlSerializerContract", xmlMappings, types, readerClass, readMethodNames, writerClass, writeMethodNames, serializers); if (DiagnosticsSwitches.KeepTempFiles.Enabled) { FileIOPermission.Assert(); assemblyBuilder.Save(assemblyName + ".dll"); } return writerType.Assembly; } // SxS: This method does not take any resource name and does not expose any resources to the caller. // It's OK to suppress the SxS warning. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [ResourceExposure(ResourceScope.None)] static MethodInfo GetMethodFromType(Type type, string methodName, Assembly assembly) { MethodInfo method = type.GetMethod(methodName); if (method != null) return method; MissingMethodException missingMethod = new MissingMethodException(type.FullName, methodName); if (assembly != null) { throw new InvalidOperationException(Res.GetString(Res.XmlSerializerExpired, assembly.FullName, assembly.CodeBase), missingMethod); } throw missingMethod; } internal static Type GetTypeFromAssembly(Assembly assembly, string typeName) { typeName = GeneratedAssemblyNamespace + "." + typeName; Type type = assembly.GetType(typeName); if (type == null) throw new InvalidOperationException(Res.GetString(Res.XmlMissingType, typeName, assembly.FullName)); return type; } internal bool CanRead(XmlMapping mapping, XmlReader xmlReader) { if (mapping == null) return false; if (mapping.Accessor.Any) { return true; } TempMethod method = methods[mapping.Key]; return xmlReader.IsStartElement(method.name, method.ns); } string ValidateEncodingStyle(string encodingStyle, string methodKey) { if (encodingStyle != null && encodingStyle.Length > 0) { if (methods[methodKey].isSoap) { if (encodingStyle != Soap.Encoding && encodingStyle != Soap12.Encoding) { throw new InvalidOperationException(Res.GetString(Res.XmlInvalidEncoding3, encodingStyle, Soap.Encoding, Soap12.Encoding)); } } else { throw new InvalidOperationException(Res.GetString(Res.XmlInvalidEncodingNotEncoded1, encodingStyle)); } } else { if (methods[methodKey].isSoap) { encodingStyle = Soap.Encoding; } } return encodingStyle; } internal static FileIOPermission FileIOPermission { get { if (fileIOPermission == null) fileIOPermission = new FileIOPermission(PermissionState.Unrestricted); return fileIOPermission; } } internal object InvokeReader(XmlMapping mapping, XmlReader xmlReader, XmlDeserializationEvents events, string encodingStyle) { XmlSerializationReader reader = null; try { encodingStyle = ValidateEncodingStyle(encodingStyle, mapping.Key); reader = Contract.Reader; reader.Init(xmlReader, events, encodingStyle, this); if (methods[mapping.Key].readMethod == null) { if (readerMethods == null) { readerMethods = Contract.ReadMethods; } string methodName = (string)readerMethods[mapping.Key]; if (methodName == null) { throw new InvalidOperationException(Res.GetString(Res.XmlNotSerializable, mapping.Accessor.Name)); } methods[mapping.Key].readMethod = GetMethodFromType(reader.GetType(), methodName, pregeneratedAssmbly ? this.assembly : null); } return methods[mapping.Key].readMethod.Invoke(reader, emptyObjectArray); } catch (SecurityException e) { throw new InvalidOperationException(Res.GetString(Res.XmlNoPartialTrust), e); } finally { if (reader != null) reader.Dispose(); } } internal void InvokeWriter(XmlMapping mapping, XmlWriter xmlWriter, object o, XmlSerializerNamespaces namespaces, string encodingStyle, string id) { XmlSerializationWriter writer = null; try { encodingStyle = ValidateEncodingStyle(encodingStyle, mapping.Key); writer = Contract.Writer; writer.Init(xmlWriter, namespaces, encodingStyle, id, this); if (methods[mapping.Key].writeMethod == null) { if (writerMethods == null) { writerMethods = Contract.WriteMethods; } string methodName = (string)writerMethods[mapping.Key]; if (methodName == null) { throw new InvalidOperationException(Res.GetString(Res.XmlNotSerializable, mapping.Accessor.Name)); } methods[mapping.Key].writeMethod = GetMethodFromType(writer.GetType(), methodName, pregeneratedAssmbly ? assembly : null); } methods[mapping.Key].writeMethod.Invoke(writer, new object[] { o }); } catch (SecurityException e) { throw new InvalidOperationException(Res.GetString(Res.XmlNoPartialTrust), e); } finally { if (writer != null) writer.Dispose(); } } internal Assembly GetReferencedAssembly(string name) { return assemblies != null && name != null ? (Assembly)assemblies[name] : null; } internal bool NeedAssembyResolve { get { return assemblies != null && assemblies.Count > 0; } } internal sealed class TempMethodDictionary : DictionaryBase { internal TempMethod this[string key] { get { return (TempMethod)Dictionary[key]; } } internal void Add(string key, TempMethod value) { Dictionary.Add(key, value); } } } sealed class XmlSerializerCompilerParameters { bool needTempDirAccess; CompilerParameters parameters; XmlSerializerCompilerParameters(CompilerParameters parameters, bool needTempDirAccess) { this.needTempDirAccess = needTempDirAccess; this.parameters = parameters; } internal bool IsNeedTempDirAccess { get { return this.needTempDirAccess; } } internal CompilerParameters CodeDomParameters { get { return this.parameters; } } internal static XmlSerializerCompilerParameters Create(string location) { CompilerParameters parameters = new CompilerParameters(); parameters.GenerateInMemory = true; if (string.IsNullOrEmpty(location)) { #if CONFIGURATION_DEP XmlSerializerSection configSection = ConfigurationManager.GetSection(ConfigurationStrings.XmlSerializerSectionPath) as XmlSerializerSection; location = configSection == null ? location : configSection.TempFilesLocation; #endif // Trim leading and trailing white spaces (VSWhidbey 229873) if (!string.IsNullOrEmpty(location)) { location = location.Trim(); } } parameters.TempFiles = new TempFileCollection(location); return new XmlSerializerCompilerParameters(parameters, string.IsNullOrEmpty(location)); } internal static XmlSerializerCompilerParameters Create(CompilerParameters parameters, bool needTempDirAccess) { return new XmlSerializerCompilerParameters(parameters, needTempDirAccess); } } class TempAssemblyCacheKey { string ns; object type; internal TempAssemblyCacheKey(string ns, object type) { this.type = type; this.ns = ns; } public override bool Equals(object o) { TempAssemblyCacheKey key = o as TempAssemblyCacheKey; if (key == null) return false; return (key.type == this.type && key.ns == this.ns); } public override int GetHashCode() { return ((ns != null ? ns.GetHashCode() : 0) ^ (type != null ? type.GetHashCode() : 0)); } } internal class TempAssemblyCache { Hashtable cache = new Hashtable(); internal TempAssembly this[string ns, object o] { get { return (TempAssembly)cache[new TempAssemblyCacheKey(ns, o)]; } } internal void Add(string ns, object o, TempAssembly assembly) { TempAssemblyCacheKey key = new TempAssemblyCacheKey(ns, o); lock (this) { if (cache[key] == assembly) return; Hashtable clone = new Hashtable(); foreach (object k in cache.Keys) { clone.Add(k, cache[k]); } cache = clone; cache[key] = assembly; } } } }