in src/Tasks/GenerateResource.cs [1615:1850]
private bool NeedSeparateAppDomain()
{
if (NeverLockTypeAssemblies)
{
Log.LogMessageFromResources(MessageImportance.Low, "GenerateResource.SeparateAppDomainBecauseNeverLockTypeAssembliesTrue");
return true;
}
foreach (ITaskItem source in _sources)
{
string extension = Path.GetExtension(source.ItemSpec);
if (String.Compare(extension, ".resources.dll", StringComparison.OrdinalIgnoreCase) == 0 ||
String.Compare(extension, ".dll", StringComparison.OrdinalIgnoreCase) == 0 ||
String.Compare(extension, ".exe", StringComparison.OrdinalIgnoreCase) == 0)
{
return true;
}
if (String.Compare(extension, ".resx", StringComparison.OrdinalIgnoreCase) == 0 ||
String.Compare(extension, ".resw", StringComparison.OrdinalIgnoreCase) == 0)
{
XmlReader reader = null;
string name = null;
try
{
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.DtdProcessing = DtdProcessing.Ignore;
reader = XmlReader.Create(source.ItemSpec, readerSettings);
while (reader.Read())
{
// Look for the <data> section
if (reader.NodeType == XmlNodeType.Element)
{
if (String.Equals(reader.Name, "data", StringComparison.OrdinalIgnoreCase))
{
// Is there an attribute called type?
string typeName = reader.GetAttribute("type");
name = reader.GetAttribute("name");
if (typeName != null)
{
Type type;
// It is likely that we've seen this type before
// we'll try our table of previously seen types
// since it is *much* faster to do that than
// call Type.GetType needlessly!
if (!_typeTable.TryGetValue(typeName, out type))
{
string resolvedTypeName = typeName;
// This type name might be an alias, so first resolve that if any.
int indexOfSeperator = typeName.IndexOf(",", StringComparison.Ordinal);
if (indexOfSeperator != -1)
{
string typeFromTypeName = typeName.Substring(0, indexOfSeperator);
string maybeAliasFromTypeName = typeName.Substring(indexOfSeperator + 1);
if (!String.IsNullOrWhiteSpace(maybeAliasFromTypeName))
{
maybeAliasFromTypeName = maybeAliasFromTypeName.Trim();
string fullName = null;
if (_aliases.TryGetValue(maybeAliasFromTypeName, out fullName))
{
resolvedTypeName = typeFromTypeName + ", " + fullName;
}
}
}
// Can this type be found in the GAC?
type = Type.GetType(resolvedTypeName, throwOnError: false, ignoreCase: false);
// Remember our resolved type
_typeTable[typeName] = type;
}
if (type == null)
{
// If the type could not be found in the GAC, then we're going to need
// to load the referenced assemblies (those passed in through the
// "References" parameter during the building of this .RESX. Therefore,
// we should create a separate app-domain, so that those assemblies
// can be unlocked when the task is finished.
// The type didn't start with "System." so return true.
Log.LogMessageFromResources
(
MessageImportance.Low,
"GenerateResource.SeparateAppDomainBecauseOfType",
(name == null) ? String.Empty : name,
typeName,
source.ItemSpec,
((IXmlLineInfo)reader).LineNumber
);
return true;
}
// If there's a type, we don't need to look at any mimetype
continue;
}
// DDB #9825.
// There's no type attribute on this <data> -- if there's a MimeType, it's a serialized
// object of unknown type, and we have to assume it will need a new app domain.
// The possible mimetypes ResXResourceReader understands are:
//
// application/x-microsoft.net.object.binary.base64
// application/x-microsoft.net.object.bytearray.base64
// application/x-microsoft.net.object.binary.base64
// application/x-microsoft.net.object.soap.base64
// text/microsoft-urt/binary-serialized/base64
// text/microsoft-urt/psuedoml-serialized/base64
// text/microsoft-urt/soap-serialized/base64
//
// Of these, application/x-microsoft.net.object.bytearray.base64 usually has a type attribute
// as well; ResxResourceReader will use that Type, which may not need a new app domain. So
// if there's a type attribute, we don't look at mimetype.
//
// If there is a mimetype and no type, we can't tell the type without deserializing and loading it,
// so we assume a new appdomain is needed.
//
// Actually, if application/x-microsoft.net.object.bytearray.base64 doesn't have a Type attribute,
// ResxResourceReader assumes System.String, but for safety we don't assume that here.
string mimeType = reader.GetAttribute("mimetype");
if (mimeType != null)
{
if (NeedSeparateAppDomainBasedOnSerializedType(reader))
{
Log.LogMessageFromResources
(
MessageImportance.Low,
"GenerateResource.SeparateAppDomainBecauseOfMimeType",
(name == null) ? String.Empty : name,
mimeType,
source.ItemSpec,
((IXmlLineInfo)reader).LineNumber
);
return true;
}
}
}
else if (String.Equals(reader.Name, "assembly", StringComparison.OrdinalIgnoreCase))
{
string alias = reader.GetAttribute("alias");
string fullName = reader.GetAttribute("name");
if (!String.IsNullOrWhiteSpace(alias) && !String.IsNullOrWhiteSpace(fullName))
{
alias = alias.Trim();
fullName = fullName.Trim();
_aliases[alias] = fullName;
}
}
}
}
}
catch (XmlException e)
{
Log.LogMessageFromResources
(
MessageImportance.Low,
"GenerateResource.SeparateAppDomainBecauseOfExceptionLineNumber",
source.ItemSpec,
((IXmlLineInfo)reader).LineNumber,
e.Message
);
return true;
}
#if FEATURE_BINARY_SERIALIZATION
catch (SerializationException e)
{
Log.LogMessageFromResources
(
MessageImportance.Low,
"GenerateResource.SeparateAppDomainBecauseOfErrorDeserializingLineNumber",
source.ItemSpec,
(name == null) ? String.Empty : name,
((IXmlLineInfo)reader).LineNumber,
e.Message
);
return true;
}
#endif
catch (Exception e)
{
// DDB#9819
// Customers have reported the following exceptions coming out of this method's call to GetType():
// System.Runtime.InteropServices.COMException (0x8000000A): The data necessary to complete this operation is not yet available. (Exception from HRESULT: 0x8000000A)
// System.NullReferenceException: Object reference not set to an instance of an object.
// System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
// We don't have reproes, but probably the right thing to do is to assume a new app domain is needed on almost any exception.
// Any problem loading the type will get logged later when the resource reader tries it.
//
// XmlException or an IO exception is also possible from an invalid input file.
if (ExceptionHandling.IsCriticalException(e))
throw;
// If there was any problem parsing the .resx then log a message and
// fall back to using a separate AppDomain.
Log.LogMessageFromResources
(
MessageImportance.Low,
"GenerateResource.SeparateAppDomainBecauseOfException",
source.ItemSpec,
e.Message
);
// In case we need more information from the customer (given this has been heavily reported
// and we don't understand it properly) let the usual debug switch dump the stack.
if (Environment.GetEnvironmentVariable("MSBUILDDEBUG") == "1")
{
Log.LogErrorFromException(e, /* stack */ true, /* inner exceptions */ true, null);
}
return true;
}
finally
{
reader?.Close();
}
}
}
return false;
}