How to set up a HintPath from TFS root

5.3k views Asked by At

I'm putting together a template project in Visual Studio for use by my department. The project needs to reference some common libraries that are stored elsewhere in TFS. The problem is that the template may get used in a wide variety of locations, and I'm having trouble trying to reliably set up HintPaths to handle all locations.

The templated project needs to be able to find the common libraries both locally and in TFS, for use in builds. Currently, in our existing applications, the references look like this:

<Reference Include="Company.Common">
  <SpecificVersion>False</SpecificVersion>
  <HintPath>..\..\..\..\..\..\Core Components\Libraries\Company.Common\Latest\Company.Common.dll</HintPath>
</Reference>

But the number of parents needed to traverse to get to the root can vary.

Instead of setting up 50 conditional paths for ../, ../../, ../../../, and so on, my first thought was to set up an absolute reference. Working Folders are standardized in our organization, so locally, the reference can always be found at C:\Projects\Core Components\...

But this won't work for server builds. So I'm thinking I need some sort of environment variable that works out to $/. I'm picturing something like this:

<Choose>
  <When Condition="Exists('C:\Projects')">
    <ItemGroup>
      <Reference Include="Company.Common">
        <HintPath>C:\Projects\Core Components\Libraries\Company.Common\Latest\Company.Common.dll</HintPath>
      </Reference>
    </ItemGroup>
  </When>
  <Otherwise>
    <ItemGroup>
      <Reference Include="Company.Common">
        <HintPath>$(TFSRoot)\Core Components\Libraries\Company.Common\Latest\Company.Common.dll</HintPath>
      </Reference>
    </ItemGroup>
  </Otherwise>
</Choose>

But I can't figure out how to accomplish that.

Update:

Eventually, we did set up an internal Nuget server. I suggest to anyone with the same dilemma to just tackle whatever red tape holds you back from setting up Nuget. We spent 3 years living with this hacky way of doing things and there was always some new wrinkle requiring manual intervention.

2

There are 2 answers

1
Dylan Smith On BEST ANSWER

I have two suggestions for how to solve this. The Good Way and the Better Way.

The Good Way (and most common), is if you have some shared library X, and you need to use it in Applications A, B, and C. Under Project A you would have a lib folder where you check in a copy of X.dll. Project B has it's own lib folder and it's own copy of X.dll (not necessarily the same version of X that A depends on). And so on. In this model it's up to the maintainers of A/B/C to choose when to pull in a new version of X and update their lib folder.

The Better Way is to use NuGet (a package manager). Project X would publish each new version to a NuGet feed somewhere, and A/B/C would subscribe to that NuGet feed and Visual Studio / TFS Build will automatically download the NuGet packages as needed. This gives some extra flexibility too, since Project A can either say "I depend on X ver 3.2" or it can say "I depend on the latest version of X" and NuGet does the work.

0
Nick Wilton On

There are 2 ways I can think of to achieve what you are looking for. One is to use the in-built VS macros the other is to create an Environment variable on the build server and then reference it in your project or MSBuild file:

<Reference Include="EntityFramework.SqlServer">
  <HintPath>..\..\packages\EntityFramework.6.1.2\lib\net45\EntityFramework.SqlServer.dll</HintPath>
  <HintPath>$(SolutionDir)packages\EntityFramework.6.1.2\lib\net45\EntityFramework.SqlServer.dll</HintPath>
  <HintPath>$(ENVIRONMENT_VARIABLE)packages\EntityFramework.6.1.2\lib\net45\EntityFramework.SqlServer.dll</HintPath>
</Reference>