File: AppConfig\DependentAssembly.cs
Web Access
Project: ..\..\..\src\Tasks\Microsoft.Build.Tasks.csproj (Microsoft.Build.Tasks.Core)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Xml;
using Microsoft.Build.Shared;
 
#nullable disable
 
namespace Microsoft.Build.Tasks
{
    /// <summary>
    /// Represents a single &lt;dependentassembly&gt; from the app.config file.
    /// </summary>
    internal sealed class DependentAssembly
    {
        /// <summary>
        /// The partial <see cref="AssemblyName"/>, there should be no version.
        /// Setter and Getter clone the incoming / outgoing assembly
        /// </summary>
        internal AssemblyName PartialAssemblyName
        {
            set
            {
                AssemblyNameReadOnly = value.CloneIfPossible();
                AssemblyNameReadOnly.Version = null;
            }
            get => AssemblyNameReadOnly?.CloneIfPossible();
        }
 
        /// <summary>
        /// The full <see cref="AssemblyName"/>. It is not cloned. Callers should not mutate this object.
        /// </summary>
        internal AssemblyName AssemblyNameReadOnly { get; private set; }
 
        /// <summary>
        /// The reader is positioned on a &lt;dependentassembly&gt; element--read it.
        /// </summary>
        internal void Read(XmlReader reader)
        {
            var redirects = new List<BindingRedirect>();
 
            if (BindingRedirects != null)
            {
                redirects.AddRange(BindingRedirects);
            }
 
            while (reader.Read())
            {
                // Look for the end element.
                if (reader.NodeType == XmlNodeType.EndElement && AppConfig.StringEquals(reader.Name, "dependentassembly"))
                {
                    break;
                }
 
                // Look for a <assemblyIdentity> element
                if (reader.NodeType == XmlNodeType.Element && AppConfig.StringEquals(reader.Name, "assemblyIdentity"))
                {
                    string name = null;
                    string publicKeyToken = "null";
                    string culture = "neutral";
 
                    // App.config seems to have mixed case attributes.
                    while (reader.MoveToNextAttribute())
                    {
                        if (AppConfig.StringEquals(reader.Name, "name"))
                        {
                            name = reader.Value;
                        }
                        else
                        if (AppConfig.StringEquals(reader.Name, "publicKeyToken"))
                        {
                            publicKeyToken = reader.Value;
                        }
                        else
                        if (AppConfig.StringEquals(reader.Name, "culture"))
                        {
                            culture = reader.Value;
                        }
                    }
 
                    string assemblyName = String.Format(
                        CultureInfo.InvariantCulture,
                        "{0}, Version=0.0.0.0, Culture={1}, PublicKeyToken={2}",
                        name,
                        culture,
                        publicKeyToken);
 
                    try
                    {
                        AssemblyNameReadOnly = new AssemblyNameExtension(assemblyName).AssemblyName;
                    }
                    catch (System.IO.FileLoadException e)
                    {
                        // A badly formed assembly name.
                        ErrorUtilities.ThrowArgument(e, "AppConfig.InvalidAssemblyIdentityFields");
                    }
                }
 
                // Look for a <bindingRedirect> element.
                if (reader.NodeType == XmlNodeType.Element && AppConfig.StringEquals(reader.Name, "bindingRedirect"))
                {
                    var bindingRedirect = new BindingRedirect();
                    bindingRedirect.Read(reader);
                    redirects.Add(bindingRedirect);
                }
            }
            BindingRedirects = redirects;
        }
 
        /// <summary>
        /// The binding redirects.
        /// </summary>
        internal List<BindingRedirect> BindingRedirects { set; get; }
    }
}