Including a .targets file in .csproj to globally define project & MSBuild variables - c#

I need to have a single place to define variables for a solution that has about 13 projects, each having a varying combination of external dependencies from the same few locations. Right now, it's easy enough to include these as a variable in a PropertyGroup, but if something changes (like a version number), we don't want to have to update each project file with that change.
I tried creating a targets file that has the variables that get used from project to project and included it into the csproj file, just before the assembly references. This appears to have worked beautifully in a website project, but not in a class library project. The references are not found.
How am I supposed to do this in a way that's safe and usable across project types? (No, Nuget is not an option in this case.)
Example of the Global Targets file:
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Product1Version>02.01.01</Product1Version>
<Product2Version>03.02.01</Product2Version>
<ReferencesPath>..\..\References</ReferencesPath>
<Product1ReferencePath>$(ReferencesPath)\Product1\$(Product1Version)</Product1ReferencePath>
<Product2ReferencePath>$(ReferencesPath)\Product2\$(Product2Version)</Product2ReferencePath>
</PropertyGroup>
</Project>
Here is an example of how I intend to use this in a csproj file:
<Import Project="..\..\Build\SolutionReferences.targets" Condition="false" />
<ItemGroup>
<Reference Include="Product1">
<SpecificVersion>False</SpecificVersion>
<HintPath>$(Product1ReferencePath)\Product1.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Product2">
<SpecificVersion>False</SpecificVersion>
<HintPath>$(Product2ReferencePath)\Product2.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>

Ugh... All I had to do was remove Condition="false" from the Import command. :(

Related

Custom property in Directory.Build.props doesn't work in HintPath of a reference

I have a Directory.Build.props located in the solution directory of my project in which I defined the following PropertyGroup with a custom property PureConfiguration:
<Project>
<PropertyGroup Condition="$(Configuration.StartsWith('Debug'))">
<PureConfiguration>Debug</PureConfiguration>
</PropertyGroup>
</Project>
In my project I have the following reference defined:
<ItemGroup>
<Reference Include="MyAwesomeReference">
<HintPath>..\..\Runtime\$(PureConfiguration)\MyAwesomeReference\MyAwesomeReference.dll</HintPath>
</Reference>
</ItemGroup>
Now when compiling it can't find the MyAwesomeReference.dll assembly (the file exists at this location, that is not the issue).
Through a
<Target>
<Message Text="$(PureConfiguration)" />
</Target>
I can see that in the build console Debug is being outputed so the property is set.
Why does the HintPath then not work? When replacing $(PureConfiguartion) with Debug the error goes away and the project builds. So somehow when loading the reference this property is not set until then? Is there some kind of order that I have to consider?
#JonathanDodds I realized that my Directory.build.props file was actually placed in the wrong folder. Silly mistake on my side! I moved it to the correct location and the references started working. Thanks a lot for your help! The <Import Project="$([MSBuild]::GetPathOfFileAbove('$(MSBuildThisFile)', '$(MSBuildThisFileDirectory)../')) /> was very helpful at the end!

How to reference external dll and xml comments in dotnet core

So i am using this
<ItemGroup>
<Reference Include="..\bibliotecas\ByteBank.Modelos.dll" />
</ItemGroup>
to reference an external api, and its working but i can't see the comments from the xml.
How to reference the XML file of an external api on dotnet.core ?
Have a look this document.
Basically, you need to config GenerateDocumentationFile element to the <PropertyGroup> section of your .csproj project file:
<GenerateDocumentationFile>true</GenerateDocumentationFile>
And try to add a dll reference like below:
<ItemGroup>
<Reference Include="ByteBank.Modelos">
<HintPath>..\bibliotecas\ByteBank.Modelos.dll</HintPath>
</Reference>
</ItemGroup>

How to Multi target a library project with WPF controls

I have a class library project that needs to target .NET 3.5 and .NET 4.0, and the way it is done now is the typical way of creating separate projects per target framework and linking files in each project to the same source.
I would like to take advantage of the new csproj format that has come out with .NET Core projects because multitargeting is much simpler with the new csproj format.
I created a new Class Library (.NET Core) project and started to try porting my existing library over.
I don't really need to target .netcoreapp2.0, so my target frameworks look like this
<PropertyGroup>
<TargetFrameworks>net35;net40</TargetFrameworks>
</PropertyGroup>
and I have the following block of code to help with the .NET 3.5 oddities with the new csproj format.
<PropertyGroup>
<FrameworkPathOverride Condition="'$(TargetFramework)' == 'net35'">C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\Client</FrameworkPathOverride>
</PropertyGroup>
So far so good. Where things started going downhill is the fact that my class library has WPF Controls. I was getting compile errors because it couldn't find System.Windows and other WPF related items.
I found I could add references to other windows assemblies, so I added the following
<ItemGroup>
<Reference Include="PresentationFramework" />
<Reference Include="PresentationCore" />
<Reference Include="WindowsBase" />
</ItemGroup>
This got rid of most of my errors, but now I am getting errors like The name 'InitializeComponent' does not exist in the current context
Some WPF items migrated to a new library System.Xaml starting at .NET 4.0
The error The name 'InitializeComponent' does not exist in the current context is being thrown only when the .NET 4.0 target is being built.
To fix this, the following block needs to be added to the csproj file
<ItemGroup Condition="'$(TargetFramework)'=='net40'">
<Reference Include="System.Xaml" />
</ItemGroup>
Also, the xaml pages need to be built as a page, so the following also needs to be added to the csproj file
All xaml files that need to be compiled as page.
<ItemGroup>
...
<Page Include="Path\to\SomeWindow.xaml" />
<Page Include="Path\to\SomeOtherWindow.xaml" />
...
</ItemGroup>
This will remove the xaml files from your solution explorer, so a workaround was found here that adds the following blocks to get xaml pages built but still showing up in the Solution Explorer.
<ItemGroup>
<Page Update="#(Page)" SubType="Designer" Generator="MSBuild:Compile" />
</ItemGroup>
<ItemGroup>
<None Include="#(Page)" />
</ItemGroup>

Visual Studio does not display references from targets in Solution Explorer

Here is a part of my .csproj:
<Project DefaultTargets="Build" InitialTargets="MyTarget" xmlns="...">
<Target Name="MyTarget" DependsOnTargets="Include_Ver1;Include_Ver2"/>
<Target Name="Include_Ver1" Condition="...">
<ItemGroup>
<COMReference Include="Ref">
1st_Version
</COMReference>
</ItemGroup>
</Target>
<Target Name="Include_Ver2" Condition="...">
<ItemGroup>
<COMReference Include="Ref">
2nd_Version
</COMReference>
</ItemGroup>
</Target>
I can use library functions and project builds correctly, but reference does not appear in "References" block inside visual studio solution explorer. How can I force Intellisense parse references in Targets?
Try with different References and below hintpath ,specific version node elements.Make sure the *.csproj is not write only under any Version control system like SVN etc.
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Owin, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Microsoft.Owin.dll</HintPath>
</Reference>
</ItemGroup>
VS doesn't display them because the solution explorer basically shows what it gets after parsing the project file. Parsing != executing, so the reference added in a target is not seen as it never executed - which makes sense, VS cannot guess if the target will even be executed or not and it cannot just start executing random builds to figure out if the reference will be added.
Do you really need a target? ItemGroups can have conditions too, maybe this is sufficient for you?
<ItemGroup Condition="...">
<COMReference Include="Ref">
1st_Version
</COMReference>
</ItemGroup>

Visual Studio Project: How to include a reference for one configuration only?

Env.: VS2008 C# project
I need to build my app for use in 2 different environments. In one of those environments, I need to use a 3rd party DLL assembly.
I could isolate the code that uses this DLL using #if blocks. But how do I conditionally include the reference to the DLL in the CS project file?
Edit: womp has a good point in his comment. I turned into a separate question: Will the referenced DLL be loaded at all if it's never called?
TIA,
Unload the project and open it as .XML
Locate the reference item tag and add a Condition attribute.
For instance:
<ItemGroup>
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml" />
<Reference Include="MyUtilities.Debug"
Condition="'$(Configuration)'=='Debug'"/>
</ItemGroup>
Notice the last reference now has a condition.
I know this is an old post, but in case anyone else finds it before they find the answer, like I did, it's this: you need to use the "Choose" element in the project file:
link
You can define both conditional references and conditional compilation in one place, so you don't have to use #if's in your code.
It works in SharpDevelop, and since it's MS's documentation I assume it works in Visual Studio.
The following, in the csproj file references itemgroup works in vs 2008 for me:-
<Reference Include="DRLClasses, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL" Condition=" '$(Configuration)' == 'Debug' ">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\Visual Studio User Library\Debug\DRLClasses.dll</HintPath>
</Reference>
<Reference Include="DRLClasses, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL" Condition=" '$(Configuration)' == 'Release' ">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\Visual Studio User Library\Release\DRLClasses.dll</HintPath>
</Reference>
Inspired by the question and answer shown here, you can add <Choose> and <When Condition> commands around the part you want to be conditionally run. For example:
<Choose>
<When Condition="$(USEDLL) == true">
<ItemGroup>
<EmbeddedResource Include="test.dll">
<LogicalName>test.dll</LogicalName>
</EmbeddedResource>
</ItemGroup>
</When>
</Choose>
Then in the CLI, simply use the /p property in MSBuild like this:
MSBuild "C:\myproject\myproject.sln" /p:USEDLL=true
...or if you don't want the DLL, simply:
MSBuild "C:\myproject\myproject.sln" /p:USEDLL=false

Categories