Visual Studio 2017 and the new .csproj InternalsVisibleTo - msbuild

Where do I put InternalsVisibleTo from AssemblyInfo in the new Visual Studio 2017 .csproj project file?

Just in case anyone would like to put InternalsVisibleTo within a .csproj file instead of AssemblyInfo.cs (a possible scenario is to have a naming convention between a project under test and a test project), you can do it like this:
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>$(MSBuildProjectName).Test</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
Having this the following code will be generated
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyProject.Test")]
inside auto-generated AssemblyInfo.cs (e.g. for Debug configuration and .NET Standard 2.0 target)
/obj/Debug/netstandard2.0/MyProject.AssemblyInfo.cs
Additional Info
In case you're on .NET Core 3.1 and this approach isn't working, you may have to explicitly generate assembly info by adding the following to your .csproj file:
<PropertyGroup>
<!-- Explicitly generate Assembly Info -->
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
</PropertyGroup>

As of .NET 5 (and newer .NET versions) this actually works once added to your csproj:
<ItemGroup>
<InternalsVisibleTo Include="YourProject.Tests.Unit" />
</ItemGroup>
Work and discussion around this feature can be seen on this PR on dotnet's GitHub repo.

To clarify Hans Passant's comment above, you simply have to add InternalsVisibleTo to any cs file in your project. For example, I created an AssemblyInfo.cs file in the root of the project and then added the following content (only):
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=<ADD_KEY_HERE>")]

Related

Where do I set version of Asp.NET Core project? [duplicate]

Since dotnet core moved back to the .csproj format, there is a new autogenerated MyProject.AssemblyInfo.cs which contains, among others:
[assembly: AssemblyCompany("MyProject")]
[assembly: AssemblyVersion("1.0.0.0")]
Note that this is automatically regenerated every build.
Previously, the file was found in the /obj/ directory, now it appears to be only in memory as the file can't be found on disk and clicking the error message does not open any file.
This is the error message:
Since they are defined there, I can't define them myself in the classical AssemblyInfo.cs.
Where/how can I define the Company and Version of a project?
As you've already noticed, you can control most of these settings in .csproj.
If you'd rather keep these in AssemblyInfo.cs, you can turn off auto-generated assembly attributes.
<PropertyGroup>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
If you want to see what's going on under the hood, checkout Microsoft.NET.GenerateAssemblyInfo.targets inside of Microsoft.NET.Sdk.
Those settings have moved into the .csproj file.
By default, they don't show up but you can discover them from Visual Studio 2017 in the project properties Package tab.
Once saved those values can be found in MyProject.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<Version>1.2.3.4</Version>
<Authors>Author 1</Authors>
<Company>Company XYZ</Company>
<Product>Product 2</Product>
<PackageId>MyApp</PackageId>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
<FileVersion>3.0.0.0</FileVersion>
<NeutralLanguage>en</NeutralLanguage>
<Description>Description here</Description>
<Copyright>Copyright</Copyright>
<PackageLicenseUrl>License URL</PackageLicenseUrl>
<PackageProjectUrl>Project URL</PackageProjectUrl>
<PackageIconUrl>Icon URL</PackageIconUrl>
<RepositoryUrl>Repo URL</RepositoryUrl>
<RepositoryType>Repo type</RepositoryType>
<PackageTags>Tags</PackageTags>
<PackageReleaseNotes>Release</PackageReleaseNotes>
</PropertyGroup>
In the file explorer properties information tab, FileVersion is shown as "File Version" and Version is shown as "Product version"
I do the following for my .NET Standard 2.0 projects.
Create a Directory.Build.props file (e.g. in the root of your repo)
and move the properties to be shared from the .csproj file to this file.
This also enables central management of these shared properties in a multi project solution, allowing for example to set the copyright and/or version numbers only once for all projects.
MSBuild will pick it up automatically and apply them to the autogenerated AssemblyInfo.cs.
They also get applied to the nuget package when building one with dotnet pack or via the UI in Visual Studio 2017.
See https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build
Example:
<Project>
<PropertyGroup>
<Company>Some company</Company>
<Copyright>Copyright © 2020</Copyright>
<AssemblyVersion>1.0.0.1</AssemblyVersion>
<FileVersion>1.0.0.1</FileVersion>
<Version>1.0.0.1</Version>
<!-- ... -->
</PropertyGroup>
</Project>
You can always add your own AssemblyInfo.cs, which comes in handy for InternalsVisibleToAttribute, CLSCompliantAttribute and others that are not automatically generated.
Adding AssemblyInfo.cs to a Project
In Solution Explorer, right click on <project name> > Add > New Folder.
Name the folder "Properties".
Right click on the "Properties" folder, and click Add > New Item....
Select "Class" and name it "AssemblyInfo.cs".
Suppressing Auto-Generated Attributes
If you want to move your attributes back to AssemblyInfo.cs instead of having them auto-generated, you can suppress them in MSBuild as natemcmaster pointed out in his answer.
Adding to NightOwl888's answer, you can go one step further and add an AssemblyInfo class rather than just a plain class:
I want to extend this topic/answers with the following. As someone mentioned, this auto-generated AssemblyInfo can be an obstacle for the external tools. In my case, using FinalBuilder, I had an issue that AssemblyInfo wasn't getting updated by build action. Apparently, FinalBuilder relies on ~proj file to find location of the AssemblyInfo. I thought, it was looking anywhere under project folder. No. So, changing this
<PropertyGroup>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
did only half the job, it allowed custom assembly info if built by VS IDE/MS Build. But I needed FinalBuilder do it too without manual manipulations to assembly info file. I needed to satisfy all programs, MSBuild/VS and FinalBuilder.
I solved this by adding an entry to the existing ItemGroup
<ItemGroup>
<Compile Remove="Common\**" />
<Content Remove="Common\**" />
<EmbeddedResource Remove="Common\**" />
<None Remove="Common\**" />
<!-- new added item -->
<None Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
Now, having this item, FinalBuilder finds location of AssemblyInfo and modifies the file. While action None allows MSBuild/DevEnv ignore this entry and no longer report an error based on Compile action that usually comes with Assembly Info entry in proj files.
C:\Program Files\dotnet\sdk\2.0.2\Sdks\Microsoft.NET.Sdk\build\Microsoft.NET.Sdk.DefaultItems.targets(263,5):
error : Duplicate 'Compile' items were included. The .NET SDK includes 'Compile' items from your project directory by default.
You can either remove these items from your project file, or set the 'EnableDefaultCompileItems' property to 'false' if you want to explicitly include them in your project file.
For more information, see https://aka.ms/sdkimplicititems. The duplicate items were: 'AssemblyInfo.cs'
Thanks, this helped me a lot.
In my case, building the project Blazor Server Side Website was successful both on Release and Debug, but publishing the website still failed with the Duplicate Attribute error, which confused me a bit.
The solution was to add <GenerateAssemblyInfo>false</GenerateAssemblyInfo> both to the .csproj and .pubxml file:
Path: <Project>/Properties/PublishProfiles/<ProfileName>.pubxml:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
...
<!-- Add the line below -->
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
</Project>
With .NET 5+, you can use AssemblyMetadata:
<AssemblyMetadata Include="Bar" Value="Baz" />

How to change assembly info in asp.net core?

I want to versioning my asp.net core app.
I followed this link: http://www.matthiaseinig.de/2013/05/20/auto-generate-fileversion-for-all-projects-in-a-solution-with-t4/ , but I want to remove project assembly info, but I didn't find it.
How to remove duplicated assembly info? I want to override asp core assemblies with another file.
BETTER SOLUTION
After a while I realize that the best solution is to use a T4 file, the version is incremented automatically after each build.
look here:
http://www.matthiaseinig.de/2013/05/20/auto-generate-fileversion-for-all-projects-in-a-solution-with-t4/
Right now properties could be defined in .csproj or using AssemblyInfo.cs, but only the one place could be used, otherwise "Duplicate" errors are generated.
If you want to use AssemblyInfo.cs, add the following into .csproj to avoid duplication errors:
<PropertyGroup>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
If you are interesting how does it work, look into GenerateAssemblyInfo task.
Otherwise, remove AssemblyInfo.cs and add the following property into your .csproj file:
<PropertyGroup>
<AssemblyVersion>1.2.3.4</AssemblyVersion>
</PropertyGroup>

How to set the default namespace in projects using project.json (.xproj)

In a standard .csproj you could go into properties and set the default namespace. How can this be achieved in a .xproj project using project.json?
With ASP.NET Core 1.0.1, you can set your default namespace in the project.json file as follows:
"tooling": {
"defaultNamespace": "Your.Name.Space"
}
The yeoman ASP.NET generator will respect this defaultNamespace when generating new classes.
For the new Visual Studio 2017 csproj tooling, you can add the following XML to change your default namespace (up in the top level <PropertyGroup> reference):
<PropertyGroup>
<Optimize>true</Optimize>
...
<RootNamespace>My.Root.Namespace</RootNamespace>
</PropertyGroup>
This is only necessary if your .csproj filename does not match your intended root namespace for the project.
AFAIK this can't be done with a project.json. You can do it with an xproj the same way you used to do it with a csproj though. Right click it in Visual Studio, and on the Application tab, change the Default namespace.

Overriding MSBuildExtensionsPath in the MSBuild task is flaky

This is already cross-posted at MS Connect:
https://connect.microsoft.com/VisualStudio/feedback/details/560451
I am attempting to override the property $(MSBuildExtensionsPath) when building a solution containing a C# web application project via msbuild. I am doing this because a web application csproj file imports the file "$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets". This file is installed by Visual Studio to the standard $(MSBuildExtensionsPath) location (C:\Program Files\MSBuild). I would like to eliminate the dependency on this file being installed on the machine (I would like to keep my build servers as "clean" as possible). In order to do this, I would like to include the Microsoft.WebApplication.targets in source control with my project, and then override $(MSBuildExtensionsPath) so that the csproj will import this included version of Microsoft.WebApplication.targets. This approach allows me to remove the dependency without requiring me to manually modify the web application csproj file.
This scheme works fine when I build my solution file from the command line, supplying the custom value of $(MSBuildExtensionsPath) at the command line to msbuild via the /p flag. However, if I attempt to build the solution using the MSBuild task in a custom msbuild project file (overriding MSBuildExtensionsPath using the "Properties" attribute), it fails because the web app csproj file is attempting to import the Microsoft.WebApplication.targets from the "standard" Microsoft.WebApplication.targets location (C:\Program Files\MSBuild). Notably, if I run msbuild using the "Exec" task in my custom project file, it works. Even more notably, the FIRST time I run the build using the "MSBuild" task AFTER I have run the build using the "EXEC" task (or directly from the command line), the build works.
Has anyone seen behavior like this before? Am I crazy? Is anyone aware of the root cause of this problem, a possible workaround, or whether this is a legitimate bug in MSBuild?
Steps to Reproduce:
1) Create a new empty solution in MSVS 2008 (Fake.sln)
2) Add a new C# web application to the solution (WebApplication1.csproj)
3) Close MSVS
4) Copy the contents of "C:\Program Files\MSBuild\" to a directory called "MSBuildExtensions" in the directory containing your solution.
5) rename the directory "C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\WebApplications" so that WebApplication1.csproj will not be able to import Microsoft.WebApplication.targets from that location.
6) Create a custom MSBuild project file called "TestBuild.proj" in the same directory as the solution. It should have the following content:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="BuildMSBuild">
<PropertyGroup>
<MSBuildExtensionsPath>$(MSBuildProjectDirectory)\MSBuildExtensions\</MSBuildExtensionsPath>
<BuildThis>Fake.sln</BuildThis>
</PropertyGroup>
<Target Name="BuildMSBuild">
<MSBuild Projects="$(BuildThis)" Properties="MSBuildExtensionsPath=$(MSBuildExtensionsPath);" Targets="Clean" />
<MSBuild Projects="$(BuildThis)" Properties="MSBuildExtensionsPath=$(MSBuildExtensionsPath);"/>
</Target>
</Project>
7) execute "msbuild TestBuild.proj" from a MSVS command prompt (note: the build may succeed the first time, but will fail if you run more than once)
Did you try setting the environment variable MSBuildExtensionPath in the CMD prompt and then running your build?
For example:
C:\> SET MSBuildExtensionsPath=C:\My\MSBuild\Extensons
Then on this project file:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build">
<Message Text='MSBuildExtensionsPath="$(MSBuildExtensionsPath)"' />
</Target>
</Project>
you will get the following output:
c:\Users\chuckeng\Desktop\ConsoleApplication1>"C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe" my.proj
Microsoft (R) Build Engine Version 3.5.30729.4926
[Microsoft .NET Framework, Version 2.0.50727.4927]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 6/25/2010 1:04:05 PM.
Project "c:\my.proj" on node 0 (default targets).
MSBuildExtensionsPath="C:\My\MSBuild\Extensons"
Done Building Project "c:\my.proj" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.03
This works from v4.0 as well. Although, support is generally better in v4.0 for things like this. And, v4.0 is 100% backward compatible (bugs not withstanding). So, you can build your v3.5 and prior projects with v4.0. Just select ToolsVersion 3.5.
msbuild my.proj /tv:3.5
Hope this helps...
Chuck England
Visual Studio
Program Manager - MSBuild
This is a bug in MSBuild 3.5 but it is fixed in MSBuild 4.
If you can, switch to MSBuild 4 (you still can compile your 3.5 projects), otherwise you'll have to override the property in the project file.
It works fine if you override MSBuildExtensionsPath directly in the web app .csproj file.
<PropertyGroup>
<MSBuildExtensionsPath>C:\Users\madgnome\Desktop\msbuild</MSBuildExtensionsPath>
<!-- It works too with relative path -->
<!--<MSBuildExtensionsPath>..\msbuild</MSBuildExtensionsPath>-->
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
Don't know if this might help anyone in the future, but I was able to use the following at the top of my file and it works as I would expect in both 32 and 64 bit build environments.
<PropertyGroup>
<MSBuildExtensionsPath Condition=" '$(MSBuildExtensionsPath64)' != '' ">$(MSBuildExtensionsPath64)</MSBuildExtensionsPath>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks"/>

How do I add an MSBuild .proj file to my solution?

Does anyone know how to add a an MSBuild .proj file to my solution?
I was just given existing code from a vendor with a solution that references an MSBuild .proj file as one of its projects. When I open the solution, the project shows as (unavailable). It appears that I need to install some sort of project template to get this project to open correctly. I installed the Codeplex MSBuild Template, but this doesn't appear to be it.
Any ideas?
If you don't need IDE support, it's possible to do this using MSBuild solution extension targets.
Create a file named "before.SolutionName.sln.targets" with the following code:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ProjectReference Include="CustomProject\CustomProject.proj">
<AdditionalProperties>Configuration=$(Configuration); Platform=AnyCPU</AdditionalProperties>
<Configuration>$(Configuration)</Configuration>
<Platform>AnyCPU</Platform>
</ProjectReference>
</ItemGroup>
</Project>
When your solution is built at command line by MSBuild (ie/ build server) the custom MSBuild project will be pulled into the temporary in-memory project file that MSBuild converts the solution into.
I actually got it to work! I re-started Visual Studio and still saw that the projects were unavailable after installing the MSBuild Template mentioned above. I had to manually reload the projects. That fixed the issue.