handwritten msbuild ignores rootnamespace for c# dll - c#

I am working on an automated c# build that requires me to write/generate the csproj file and then compile it using the command line. For some reason while the dll is created without issue, the class it contains is dumped into the global namespace instead of the one I have specified in . Does anyone have any idea what might be going on here?
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutputType>Library</OutputType>
<RootNamespace>SimpleDependency.Test</RootNamespace>
<AssemblyName>simpledependency.test</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<ItemGroup>
<Compile Include="*.cs" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>Bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
I have msbuild set to .net 4.0, and am running this command on the command line:
msbuild /property:Configuration=Release /property:Platform=AnyCPU
I know that it generates the dll successfully because I then have another dependent project that uses the class I have defined in this project, but if I include:
using SimpleDependency.Test;
in that code, I get compile errors saying it cannot find namespace 'SimpleDependency'. Without this using statement, it compiles fine and works. Anyone have any thoughts?

Run MSBuild using the /preprocess:flattened.proj flag. Then load up the resulting file in an XML editor. My recent experience is that when properties are not being seen, it's overwritten someplace later (e.g. setting rather than appending to it) or something about conditions. That's a good start. You might also try getting MSBuildExplorer3 and see if that turns up anything. I'm not familiar with C# projects, but I think you should find where $(RootNamespace) is actually used for its effect, and trace backwards: is it ignored due to a condition, not getting the target variation you expected, etc. Once you know the lay of the land, run MSBuild with /verbosity:diag and grep through that for the target where it's (supposed to be) used, and see what it was thinking.

Copying the feedback from Pierre-Luc into an answer: The rootnamespace appears to only be a suggestion to the IDE to inject whenever creating classes. If the .cs files do not have a namespace specified, rootnamespace will not become the namespace for those classes. More information about that problem in this question.

Related

Cannot debug netstandard2.0 project in Visual Studio 2019

I'm building a project with the following in the CSPROJ file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<PlatformTarget>AnyCPU</PlatformTarget>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>basic_example</RootNamespace>
<ImplicitUsings>disable</ImplicitUsings>
<StartupObject>basic_example.LoopThroughInvalidFileChars</StartupObject>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="2.14.0" />
</ItemGroup>
</Project>
I'm interested in debugging a source file in this project using Visual Studio 2019. Here are the details:
When I start the project without debugging, it compiles and runs fine. However when I place a breakpoint in my source code and I try to start with debugging, it basically runs my program and never stops at the breakpoint.
In my output window in Visual Studio, the following message appears:
The target process exited without raising a CoreCLR started event. Ensure that the target > process is configured to use .NET Core. This may be expected if the target process did not > run on .NET Core.
The program '[25444] basic-example.dll' has exited with code 0 (0x0).
However, I am intentionally setting the target framework to netstandard2.0. I.e. I would really like to debug it with the current project file.
Why won't Visual Studio allow me to debug this project?
Thanks to #LukeBriner's and #Dai's comments I was able to solve the problem.
As #LukeBriner mentions:
If you want to debug into it as a netstandard library then just create a dotnet core console app and call into the library in a normal way.
So that's what I did.
I had to rename all methods named Main in my class library to something else (I used Run).
I added a console app to the solution adjacent to the class library and added a project reference to the class library.
I imported the class library in my console apps' Program.cs with a using statement. I called the class I wanted to debug in the Main method of Program.cs
I modified the project file of the console application to look like the following:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>call_basic_example</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\openxml-exceptions\basic-example.csproj" />
</ItemGroup>
</Project>
I modified the project file for the class library to look like the following:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PlatformTarget>AnyCPU</PlatformTarget>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>basic_example</RootNamespace>
<ImplicitUsings>disable</ImplicitUsings>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="2.14.0" />
</ItemGroup>
</Project>
I was then finally able to debug into whichever method I wanted in the class library.

Build target used by Visual Studio to do Incremental Build via msbuild command line

I created a task in our C# Projects to auto-version projects when they are built (changes are made) in release mode. The versioning part works perfectly. However, all the projects are being built regardless if the project actually changed when done from command line. This causes projects to be versioned unnecessarily. Building in Visual Studio works, unchanged projects are not built, however we made a tool to do automated build using msbuild.exe and are using this as a temporary fix while we work on Bamboo and that method always does a blind build, even if there are no changes to the project. I need to be able to identify if changes were made to the project.
Something like
'$(wasSourceUpdated)' == 'true' or some kind of target condition to use on my custom versioning target.
Here is a sample of my versioning task in our projects
<Import Project="..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets" Condition="Exists('..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets') And '$(Configuration)|$(Platform)' == 'Release|AnyCPU' And '$(DeployOnBuild)' != 'true'" />
I also checked this and this articles to no avail.
EDIT
I need the task to run before the build is actually executed in order to stamp the generated assemblies with the new versions
EDIT 2
What I'm really looking for is the condition to run CoreCompile or to run CoreCompile again when I detect that the assembly was updated
What I've tried so far:
<Project>
<PropertyGroup>
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<_AssemblyTimestampBeforeCompile>%(IntermediateAssembly.ModifiedTime)</_AssemblyTimestampBeforeCompile>
</PropertyGroup>
<PropertyGroup>
<_AssemblyTimestampAfterCompile>%(IntermediateAssembly.ModifiedTime)</_AssemblyTimestampAfterCompile>
</PropertyGroup>
<PropertyGroup>
<_ProjectVersioned Condition="'$(_ProjectVersioned)'==''">false</_ProjectVersioned>
</PropertyGroup>
<Target Name="IncrementVersionBeforeBuild" AfterTargets="CoreCompile" Condition="'$(_AssemblyTimestampBeforeCompile)'!='$(_AssemblyTimestampAfterCompile)' and '$(_ProjectVersioned)' == 'false'">
<Message Text="Before $(_AssemblyTimestampBeforeCompile) After $(_AssemblyTimestampAfterCompile)" Importance="High"/>
<IncrementVersion
ProjectPath="$(MSBuildProjectFullPath)"
VersionRule="3.3.0.+"
FileName="Properties\AssemblyInfo.cs">
</IncrementVersion>
</Target>
<PropertyGroup>
<TaskPath>$(MSBuildThisFileDirectory)..\Tasks\AutoVersionTask\AutoVersionTask\bin\Debug</TaskPath>
</PropertyGroup>
<!-- Sample import for projects
<Import Project="..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets" Condition="Exists('..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets') And '$(Configuration)|$(Platform)' == 'Release|AnyCPU' And '$(DeployOnBuild)' != 'true'" />
-->
<UsingTask AssemblyFile="$(TaskPath)\AutoVersionTask.dll" TaskName="AutoVersionTask.IncrementVersion" />
<PropertyGroup>
<_ProjectVersioned>true</_ProjectVersioned>
</PropertyGroup>
Thanks in advance
So Thanks to Lance for getting me to understand MSBuild to the point that I understand the issue way better.
After a long time researching the default task, I ran upon this question that had the perfect solution to my issue. After applying the fix the versioning task now only runs when changes are made to the msbuild code.
The inputs and outputs are the same as the CoreCompile target and ensures that the task is only run if there were changes to the source
Here is the target I ran that works:
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<CoreCompileDependsOn>
$(CoreCompileDependsOn);
IncrementVersionBeforeBuild
</CoreCompileDependsOn>
</PropertyGroup>
<Target Name="IncrementVersionBeforeBuild"
Inputs="$(MSBuildAllProjects);
#(Compile);
#(_CoreCompileResourceInputs);
$(ApplicationIcon);
$(AssemblyOriginatorKeyFile);
#(ReferencePath);
#(CompiledLicenseFile);
#(EmbeddedDocumentation);
$(Win32Resource);
$(Win32Manifest);
#(CustomAdditionalCompileInputs)"
Outputs="#(DocFileItem);
#(IntermediateAssembly);
#(_DebugSymbolsIntermediatePath);
$(NonExistentFile);
#(CustomAdditionalCompileOutputs)"
>
<Message Text="Version Task running" Importance="High"/>
<IncrementVersion
ProjectPath="$(MSBuildProjectFullPath)"
VersionRule="3.3.0.+"
FileName="Properties\AssemblyInfo.cs">
</IncrementVersion>
</Target>
<PropertyGroup>
<TaskPath>$(MSBuildThisFileDirectory)..\Tasks\AutoVersionTask\AutoVersionTask\bin\Debug</TaskPath>
</PropertyGroup>
<UsingTask AssemblyFile="$(TaskPath)\AutoVersionTask.dll" TaskName="AutoVersionTask.IncrementVersion" />
<PropertyGroup>
<_ProjectVersioned>true</_ProjectVersioned>
</PropertyGroup>
</Project>
Normaly, we can add the script below into .csproj file:
<PropertyGroup>
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
</PropertyGroup>
<Target Name="AutoVersionWhenBuild" AfterTargets="CoreBuild"
Condition="'$(_AssemblyTimestampBeforeCompile)'!='$(_AssemblyTimestampAfterCompile)'">
<Message Importance="high" Text="Auto-version begins when changes are made!"/>
<!--<AutoVersionTask>Do your auto-version task here.</AutoVersionTask>-->
</Target>
It will be called during the build when changes are really made to the project. See this similar issue.
As for your situation:
It seems your tasks and target comes from the targets file DXTAutoIncrementVersion.targets,you can open that file and change the target in it to the format above.
In addition: Please check the relationship between tasks, targets and .targets file.
1.MSBuild uses tasks to perform these actions.
2.Targets group tasks together.
3.MSBuild includes several .targets files that contain items, properties, targets, and tasks for common scenarios.
So you can either modify your auto-version target in the xx.targets file, or use the script above, and call the auto-version task in the AutoVersionWhenBuild target. Hope it helps:)

Specify AdditionalReferencePaths from an external .target file

I have a bunch of project that requires tweaks to be build in a continuous environement.
I put every tweaks in a separate .target file to reuse this file across all projects.
At the very end of my csproj files, I put (before the closing) Project element:
This is working quite well unless I try to include additional reference path.
If I specify using command line the path (msbuild myproject.csproj /p:ReferencePath="C:\path\to\dlls"). The project compile.
My target file is :
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- some tweaks here -->
<PropertyGroup Condition="'$(CompileFor)' == 'SP2013'">
<SomeProperty>some value</SomeProperty>
<AdditionalReferencePaths>C:\path\to\dlls</AdditionalReferencePaths>
</PropertyGroup>
</Project>
But this does not works (dll cannot be resolved).
I also tried :
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<AdditionalReferencePaths Include="C:\path\to\dlls"/>
</ItemGroup>
</Project>
This is not working, because the ItemGroup element can't be out of a Target element
Lastly, I tried:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="SomeTarget" BeforeTargets="BeforeBuild">
<ItemGroup>
<AdditionalReferencePaths Include="C:\path\to\dlls"/>
</ItemGroup>
</Target>
</Project>
This still isn't working. No error, I can see the target is called in the build log, but the DLLs are still not resolved.
How to fix it?
To give a bit of context, tweaks I include in the target file allows me to compile the project against different version of DLLs. The code is a plugin of a 3rd party application (SharePoint to name it), and I want to compile for several different versions of the product. Using some conditional, I can target either a folder with one version of the product or another folder for other version of the product.
I get rid of this issue after two fixes.
The correct property wasn't AdditionalReferencePath but ReferencePath
I also have to move the Import before the first ItemGroup of my csproj. I guess this was required to have to properties set before the Reference element

C# how to install Windows.Media.Transcoding

In my current project I need to use the Windows Media Transcoding API. However, I can't manage to install it.
Here you can see I'm using the correct namespace.
using System.Windows.Media.Transcoding;
I looked around on NuGet, but couldn't find it there. I read the Microsoft page about it, but that only told me the namespace. I also couldn't find it's Assembly. Could someone please help me install it.
You can follow these instructions:
Modify the target platform by opening your .csproj file with an external editor and add the line
<TargetPlatformVersion>8.0</TargetPlatformVersion>
as for this example
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6D41F51D-5A85-4826-9868-14FB3591F280}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WindowsFormsApplication1</RootNamespace>
<AssemblyName>UseWindowsMediaTranscodingAPI</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetPlatformVersion>8.0</TargetPlatformVersion>
</PropertyGroup>
Reload the solution and add a reference to Windows Core Media DLL
This should already compile.
Additionally to be able handle events and async methods mapping you should add the reference to the system dll:
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETCore\v4.5\System.Runtime.InteropServices.WindowsRuntime
Remember that the application will work only on Windows 10.
Source: https://blogs.msdn.microsoft.com/cdndevs/2013/10/02/using-windows-8-winrt-apis-in-net-desktop-applications/

want different icons with different builds in C#

We have a product but we are doing some rebranding so we need to be able to build and maintain two versions. I used resource files combined with some #if stuff to solve the strings, images, and whatever else, but the program icon is giving me trouble. I couldn't figure it out from msdn or a google search. Thanks!
Are you referring to the application icon? You can edit your project file manually and put in code similar to the following:
<PropertyGroup>
<ApplicationIcon Condition=" '$(Configuration)' == 'Version1' ">Icon1.ico</ApplicationIcon>
<ApplicationIcon Condition=" '$(Configuration)' == 'Version2' ">Icon2.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup Condition=" '$(Configuration)' == 'Version1' ">
<Content Include="Icon1.ico" />
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' == 'Version2' ">
<Content Include="Icon2.ico" />
</ItemGroup>
Create icon files named after your config. (E.g. DebugOld.app.ico DebugBranded.app.ico, ReleaseBranded.app.ico)
Create a pre-build step:
copy "$(ProjectDir)$(ConfigurationName).app.ico" "$(ProjectDir)app.ico"
Set the icon in normal code, and you should be able to use the same techniques as you have elsewhere. You'll need both icons in the resources file (at least so I suspect) but it should work.
Alternatively, set a prebuild step to copy the appropriate icon into a common filename - e.g. copying debug.ico or release.ico into app.ico. A bit hacky, but I think it would work. That way you only end up with one icon in the finished binaries.
Yet another option: look into the build file and see how the icon is built in, then conditionalise it. Marc Gravell did this for references in MiscUtil - the project can be built targeting either .NET 2.0 or 3.5, depending on configuration. I suspect that resources could be conditionalised in a very similar way.

Categories