OK here is my problem I have 2 library and 2 project that include their .csproj (1 for Dev, 1 for Client Delivery).
I need a Defined constant to set accessible most of my class when we are with the Dev purpose (internal -> public).
I used a Directory.Build.props in my dev project directory that defined a variable and my Libraries .csproj define a constant if this variable exists.
<PropertyGroup Condition ="$(ActiveIHMMode)=='true'">
<DefineConstants>$(DefineConstants);DEV_IHM_MODE</DefineConstants>
</PropertyGroup>
I can see everything work well for my dev proj but it doesn't for my Libraries (they don't see my .props variable)
I assume there is a simple reason for it, it's because of dependencies compile order.
My directory Hierarchie is the following :
LibA
LibB
ProjectDelivery
ProjectDev
My LibA is compiled first and doesn't find any Directory.Build.props because my file is in my ProjectDev Directory, but my ProjectDev as the last element to compile finds it, but it's too late for my Lib.
First time using .props and I can't see a way to resolve it. Thanks for your future help.
First of all, to clarify a possible confusion inferred from your title, automatically importing Directory.Build.props is not a Visual Studio 2017 feature, but a MSBuild 15 feature (which is included with VS2019).
With my nitpicking out of the way, let's get technical:
The problem is not your build order. The reason Directory.Build.props is only picked up in your ProjectDev project, is because MSBuild looks in the directory of the .csproj for a file called Directory.Build.props and imports it if it finds it. If it is not found, the file is searched in the parent directory. And it keeps looking for the Directory.Build.props in the parent directory until it reaches the root, or it actually finds that file and then stops, so it only automatically imports the first Directory.Build.props found.
Your project structure, as described above, looks like this:
/LibA/
/LibA/LibA.csproj
/LibB/
/LibB/LibB.csproj
/ProjectDelivery/
/ProjectDelivery/ProjectDelivery.csproj
/ProjectDev/
/ProjectDev/ProjectDev.csproj
/ProjectDev/Directory.Build.props
Only ProjectDev gets the Directory.Build.props automatically imported; none of the other projects have a Directory.Build.props neither in their directory nor in any of their parent directories.
To fix your issue you can either move the Directory.Build.props one folder up, so that it gets automatically imported by all of your projects,
or you may import the Directory.Build.props manually by adding an Import element to your .csproj:
<Project>
<Import Project="..\ProjectDev\Directory.Build.props" />
</Project>
You can read up on more details about Directory.Build.props in the documentation.
Related
I need to use a NuGet package containing a utility for my project. It contains several binaries (EXEs and DLLs).
I've added it to my project successfully but I suspect the nupkg isn't formed correctly because I cannot use any of its DLLs or EXEs in my project without manually pointing to the package in my local NuGet cache. When compiling, none of its resources are added to the output (I assume this is because nothing is referenced in my code).
I'd like to create a wrapper project to call the binaries but I'd also like other project devs to be able to compile the solution without adjusting directory variables. Ideally, I could configure the csproj to pull in the bits directly from the local package cache. I think this would be possible by setting the Generate Path Property value to Yes in Visual Studio, but the variable cannot be found when I attempt to use an <Include/> statement in the csproj file.
Is what I'm asking possible? Namely, reference the NuGet package bits within my csproj to ensure the binaries are dropped in the compilation output? Can I do this with the Path Property, or is there something else I can do without directly committing the package's binaries into my project?
(I realize I need to work with the developer to fix whatever issue they have with their package, but I have no direct influence at the moment so this is the best I can do at the moment).
I figured this out, mostly due to misunderstanding how some of the different tags and attributes are meant to be used.
To achieve the desired effect, I did the following:
<ItemGroup>
<Content Include="$(Pkg{PackageId})\**">
<Link>{NameOfSolutionDirectory}\%(RecursiveDir)%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
Where {PackageId} is the name of the NuGet package (this step requires setting 'Generate Path Property' to 'Yes' in the package properties via Solution Explorer), and {NameOfSolutionDirectory} is the name of a folder within the solution I'd like to use for containing those bits, if you're as concerned about keeping the project as organized as I am. The {} should be excluded when replacing these values.
If you want to scope to a specific directory within the package contents, do it within the Include attribute. The ** is necessary if you want to include all files within that directory, or else you can scope by extension or whatever additional pattern you'd like.
I have two class libraries in a single solution (.NET Core). One of them (cl1) is a main library and it depends on another library (cl2). I have added a .nuspec file with the required metadata only (no dependencies, no files) for the cl1 project in the project folder (same location of .csproj file) and I have set GeneratePackageOnBuild propery to true.
Whenever I am building the class library (cl1), the .nupkg is created automatically in the debug/release folder.
When I check the generated .nupkg file, I am see two strange things:
The generated .nuspec file is different than what I have added in the project folder
cl2 is mentioned as a dependency in the newely generated .nuspec file, but the DLL for cl2 is not included in the lib folder of the .nupkg. So, whenever I consume this package in another solution, I am getting the error No packages exist with this id in source(s) for the cl2.
I have surfed in internet, but was not able to find a proper solution for the above error.
And I have added a .nuspec file [...] in the project folder(same location of .csproj file)
You have to specify the path to your own NuSpec file in the .csproj using the NuspecFile tag, otherwise it will be ignored and the package will be created with the metadata from the .csproj file instead, see reference. You need to use either a relative or an absolute path to the file, for example:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<NuspecFile>cl1.nuspec</NuspecFile>
</PropertyGroup>
</Project>
The generated .nuspec file is different than what I have added in the project folder
As already stated, your NuSpec file is probably not included. However, even if it is, there can be differences, because some information, e.g. source file locations are unnecessary and the target locations are in most cases given by the internal package file structure itself, so it is not there because it is redundant.
cl2 is mentioned as a dependency in the newely generated .nuspec file, but the dll for the cl2 is not included in the lib folder of the .nupkg. So, whenever I consume this nupkg in other solution, I am getting error " No packages exist with this id in source(s)" for the cl2.
Dependencies are meant for packages. So when NuGet restores the package it searches for other packages that this package depends on, here cl2, but there is none, hence the error. When packing a project, referenced projects are not included in the package. That is an open issue and there are workarounds that you can try.
The most reliable, but inconvenient solutions are to avoid the issue at all.
Only use a single project, everything will be included in the package
Pack each project on its own and use the generated package instead of the referenced project
i have a new visual studio solution that has around 350 projects. it takes visual studio a lot of time to compile the .sln file so i implemented Directory.Build.props to avoid copying of references that are not needed to copy to the local directory so the build can be made quicker. below is the code that im using inside the Directory.Build.props file under the root folder.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<Reference>
<Private>False</Private>
</Reference>
<ProjectReference>
<Private>False</Private>
</ProjectReference>
</ItemDefinitionGroup>
</Project>
since i placed Directory.Build.props under root folder it is being applied for all projects.
Question::
how can i exclude few projects from applying Directory.Build.props so that the references can be copied to the local.
in short i want the Directory.Build.props to be applied to only 300 projects under the solution file remaining 50 projects need to be excluded from this
how/where can i write a condition in the above code that will exclude certain projects being affected by this code
For others dealing with the same problem, there is another trick that can be used to exclude certain project from using the Directory.Build.props file found at root level.
If you add a dummy Directory.Build.props file in the project you want to exclude, then the Directory.Build.props from the root will not be used. This is because MSBuild walks the directory structure upwards from the location of your project, until it locates the first Directory.Build.props. That will be used. This behavior is documented on the Customize your build page under Search scope at the Microsoft docs.
Sample of the dummy Directory.Build.props:
<Project>
<!-- Only here so that the default Directory.Build.props will not be used. -->
</Project>
I found this to be a convenient way to solve this issue. Especially when dealing with only a few projects that need to be excluded.
I had to work around this in a bit of a hacky way.
In my example, there was a custom analyzer project I wrote that I did not want included in another set of projects. I ended up writing something like this in my Directory.Build.props:
<Project>
...
<Choose>
<When Condition="$(MSBuildProjectName)!='Analyzer' AND ...">
<ItemGroup>
<ProjectReference Include="..\Analyzer\Analyzer.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Analyzer</OutputItemType>
</ProjectReference>
</ItemGroup>
</When>
<Otherwise>
...
</Otherwise>
</Choose>
...
</Project>
Where I filled in ... with the projects I wanted it to skip.
I understand this may not be the exact answer you were looking for, but I did a ton of research and was also unable to find any way to do it the way you described. The stuff I have posted was the only way I was able to achieve the ability to exclude certain things from being applied to specific projects by filtering via name. I know that this is hacky and sucks, but it's the only thing that was able to work for me.
Also note that <Otherwise></Otherwise> may be turned into <Otherwise /> possibly, and may even be optional altogether. I left it there so that you could place stuff inside of it if needed.
When compiling a .net core Web MVC project VS / Compiler creates an assembly called [MyMvcProject].Views.dll with an AssemblyFileVersion of 0.0.0.0.
Is it possible to change the Version for this generated file (and maybe also change other Assembly properties?
UPDATE
I've added Manually AssemblyInfo.cs and edited my csproj with <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
With this constellation it seems that the data is not propagated to [MyMvcProject].Views.dll
I would like to stick with AssemblyInfo.cs because I share the this file over several projects. (Unless there's another solution to have consistent Assembly Versions over many projects).
Still would like to give [MyMvcProject].Views.dll a specific version.
Any idea?
I would like to stick with AssemblyInfo.cs because I share the this file over several projects. (Unless there's another solution to have consistent Assembly Versions over many projects).
You can use a Directory.Build.props file to achieve this. This file is recognised automatically by the dotnet build system (it's part of MSBuild) and will apply to all projects within the same directory or lower. If you want to apply a Version property for an entire solution, for example, you can drop a Directory.Build.props file next to the .sln file, with the following contents:
<Project>
<PropertyGroup>
<FileVersion>1.0.0.404</FileVersion>
</PropertyGroup>
</Project>
As you might expect, this AssemblyFileVersion property will also apply to your [MyMvcProject].Views.dll assembly.
Here's a detailed list of the AssemblyInfo properties you can specify when using this approach: AssemblyInfo properties.
Addition by #gsharp:
If there's also a version set in the project properties, then the project version will "win" over the Directory.Build.props version.
Go to your project "Properties" and on "Package" tab you have most of the properties that are in AssemblyInfo in classic .Net Framework projects like "Assembly version" and "Assembly file version".
Also you could try to use this command to build your project: dotnet publish /p:Version=1.2.3
I have a MonoAndroid10 project and it has a lot of dependencies(NuGet packages too). I would like to be able to copy all of the DLL dependencies to the output folder.
Normally in a .Net Standard 2.0 project the following
<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
would make that possible. But in the MonoAndroid project, nothing happens.
If what I posted above doesn't work for a MonoAndroid project, how could I copy everything that I need in some folder, preferably in a post-build action?
I'm trying to do this because after copying all of the required DLLs in one folder I can merge them together with ILRepack.
I've come across this today, solved by adding
<CopyNuGetImplementations>true</CopyNuGetImplementations>
to android project .csproj file (under the desired PropertyGroup section).
Note: there is no need to set CopyLocalLockFileAssemblies to ture neither in android project nor in any of the dependencies.