multiple hint paths in csproj file from an text fi

2019-02-19 15:05发布

问题:

Context : In our application there two separate dlls which are repositories of variables configured for different types of hardware .These dlls has same name and is referenced from our application, Now every time if we wanted to test the different type of hardware we have to copy the relevant dll to the location where application is running. I am looking for a workaround.

References : I have seen the following threads ,

1) .csproj multiple hint paths for an assembly

2) https://whathecode.wordpress.com/2012/10/07/conditional-project-or-library-reference-in-visual-studio/

Question: Can i declare a variable in a text file say <hardware> type1 </hardware> and import that text file in my csproj file and assign the appropriate reference to my application ?

Any help ..

Following is the test application which replicates our project. SignalPool1, SignalPool2 have the same class name and are repositories for two different hardware configurations available in two different locations of our project. If we wanted to test the hardware1 we would remove the current reference and add the reference of signal pool which is relevant there same applies for hardware2. Now to avoid this manual work i wanted to automate this process either to declare a variable on XML and access the variable in csproj file to decide which to access at the time of Compilation/Running.

Currently to avoid this problem i have a separate exe which reads the xml and decides to copy them into one common folder.This exe will be called at the time of prebuild event in our project.

// Signal Pool 1 File

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SignalPool
{
public abstract class SignalPool
{
    public abstract string PreExec();
    public abstract string PostExec();
    public abstract string VnVExec();

    public static string HWVar1 = "HWVar1";
    public static string HWVar2 = "HWVar2";
    public static string HWVar3 = "HWVar3";
    public static string HWVar4 = "HWVar4";
}

}

// Signal pool2

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace SignalPool
    {
    public abstract class SignalPool
    {
    public abstract string PreExec();
    public abstract string PostExec();
    public abstract string VnVExec();

    public static string HWVar1 = "HWVar5";
    public static string HWVar2 = "HWVar6";
    public static string HWVar3 = "HWVar7";
    public static string HWVar4 = "HWVar8";
    }
}

//Accessing pool Variables

Main File

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace TestLibraries
{
    class Program 
    {
    static void Main(string[] args)
    {

        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

        Testhardware th = new Testhardware();
        th.functionToValues();



    }

    private static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        if (args.Name.Contains("SignalPool")) //Put in the name of your assembly
        {
            //var configValue = XDocument.Parse("<config><hardware>type1</hardware></config>").Document.Descendants("hardware").First().Value;
            var configValue = XDocument.Load(@"C:\Users\ha23031\Documents\Visual Studio 2010\Projects\TestLibraries\TestLibraries\TestInfo.xml").Document.Descendants("IsRealHMI").First().Value;
            if (configValue == "false")
            {
                return System.Reflection.Assembly.LoadFile(@"C:\Users\ha23031\Documents\Visual Studio 2010\Projects\TestLibraries\SignalPool\bin\Debug\SignalPool.dll");
            }
            else if (configValue == "true")
            {
                return System.Reflection.Assembly.LoadFile(@"C:\Users\ha23031\Documents\Visual Studio 2010\Projects\SignalPool\bin\Debug\SignalPool.dll");
            }
        }
        return null;
    }


}

}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestLibraries
{
    class Testhardware : SignalPool.SignalPool
    {
    public override string PostExec()
    {
        return string.Empty;
    }

    public override string PreExec()
    {
        return string.Empty;
    }

    public override string VnVExec()
    {
        return string.Empty;
    }

    public string functionToValues()
    {
        // This is how i access variables based on the loaded variables
        string s = SignalPool.SignalPool.HWVar1;
        return string.Empty;
    }
}
}

回答1:

"Can i declare a variable in a text file say type1 and import that text file in my csproj file and assign the appropriate reference to my application ?"

Isn't that exactly what I describe in the blog post you link to?

Look for the defined variable 'SomeProject' in the configuration file 'ProjectReferences.txt' which I load from the .csproj file.

ProjectReferences.txt

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Condition="$(Configuration) == 'Debug With Project References'">
    <SomeProject>..\SomeProject</SomeProject>
  </PropertyGroup>
</Project>

.csproj file

<Import Project="..\ProjectReferences.txt" />
<Choose>
  <When Condition="Exists($(SomeProject))">
    <ItemGroup>
      <ProjectReference Include="$(SomeProject)\SomeProject.csproj">
        <Project>{6CA7AB2C-2D8D-422A-9FD4-2992BE62720A}</Project>
        <Name>SomeProject</Name>
      </ProjectReference>
    </ItemGroup>
  </When>
  <Otherwise>
    <ItemGroup>
      <Reference Include="SomeProject">
        <HintPath>..\Libraries\SomeProject.dll</HintPath>
      </Reference>
    </ItemGroup>
  </Otherwise>
</Choose>


回答2:

You need to load the correct DLL during the startup of your application, before .Net loads it for you. NET will load the default DLL as soon as an instance of that class is created. So make sure to load the proper DLL first before you access the properties. Make sure you do not access these properties in the initial class anywhere as .Net will load it then.

Something like this:

class Program
{
    static void Main(string[] args)
    {
        //var configValue = XDocument.Parse("<config><hardware>type1</hardware></config>").Document.Descendants("hardware").First().Value;
        var configValue = XDocument.Load("MyXmlConfig.xml").Document.Descendants("hardware").First().Value;
        if (configValue == "type1")
        {
            System.Reflection.Assembly.LoadFile(@"C:\TEMP\MyAssembly_Type1.dll");
        }
        else if (configValue == "type2")
        {
            System.Reflection.Assembly.LoadFile(@"C:\TEMP\MyAssembly_Type2.dll");
        }

        MyRepositoryClass.Initialize();
    }
}

static class MyRepositoryClass
{
    public static void Initialize()
    {
        var variable1 = MyAssembly.MyRepository.Variable1;
        var variable2 = MyAssembly.MyRepository.Variable2;
        var variable3 = MyAssembly.MyRepository.Variable3;
    }
}

Alternative load the DLL on demand (when .Net asks for it):

class Program
{
    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

        MyRepositoryClass.Initialize();
    }

    private static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        if (args.Name.Contains("MyAssembly")) //Put in the name of your assembly
        {
            //var configValue = XDocument.Parse("<config><hardware>type1</hardware></config>").Document.Descendants("hardware").First().Value;
            var configValue = XDocument.Load("MyXmlConfig.xml").Document.Descendants("hardware").First().Value;
            if (configValue == "type1")
            {
                return System.Reflection.Assembly.LoadFile(@"C:\TEMP\MyAssembly_Type1.dll");
            }
            else if (configValue == "type2")
            {
                return System.Reflection.Assembly.LoadFile(@"C:\TEMP\MyAssembly_Type2.dll");
            }
        }
        return null;
    }
}