Customization project build - dynamics-crm

I'm trying to get managed solution after build customization project. But in the default .target file don't specified "/packagetype" argument of SolutionPackager in a Managed Solution part:
<!-- Unmanaged solution -->
<Exec Condition="'$(SolutionType)' == '0' or '$(SolutionType)' == '2'"
Command="REM SET AssemblyVersionDefinitionFile=$(AssemblyVersionDefinitionFile)
REM SET AssemblyVersionName=$(AssemblyVersionName)
"$(SolutionPackagerDir)\SolutionPackager.exe" -a:pack -z:"$(OutDir)$(TargetName).zip" -f:"$(IntermediateOutputPath)\$(BeforeLocDir)"" />
<!-- Managed solution -->
<Exec Condition="'$(SolutionType)' == '0' or '$(SolutionType)' == '2'"
Command="REM SET AssemblyVersionDefinitionFile=$(AssemblyVersionDefinitionFile)
REM SET AssemblyVersionName=$(AssemblyVersionName)
"$(SolutionPackagerDir)\SolutionPackager.exe" -a:pack -z:"$(OutDir)$(TargetName)_managed.zip" -f:"$(IntermediateOutputPath)\$(BeforeLocDir)" -p:Managed" />
All my attempts to specify "/packagetype" argument (like '/p:Managed' or '-p:Managed') were unsuccessful. What I'm do wrong?
UPD
The Output is:
1> Solution package type did not match requested type.
1> Command line argument: Unmanaged
1> Package type: Managed
Where I can change command line argument?

You can't get managed solution after build project because you exporting unmanaged solution in your customization project. About differences in XML's read here.
As for "/packagetype" - this argument is optional. You can omitted this argument, because the package type can be read from inside the .zip file or component files. More information about solution packager here.

Related

Prevent Visual Studio from leaking pdb path in compiled exe

When I build my C# project as a release in Visual Studio, the resulting .exe contains the following string:
C:\Users\jornane\source\repos\«solution»\«project»\obj\Release\«name».pdb
The .exe file leaks my username and the path where I store the project. Is there a way I can prevent this from happening? I understand why that path would be there for Debug builds, but not for Release.
It is possible to replace the stored PDB paths using the -pathmap compiler option, for example the following generates «name».exe with the PDB path stored as .\«name».pdb, instead of using the full path.
C:\Users\«user»\source\repos\«solution»\«project»>csc -debug -pathmap:"%cd%=." «name».cs
The -pathmap option is not exposed in the IDE, but can be set into the .csproj file directly, by adding the following near the end of the file.
<Project>
<!-- ... -->
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<!-- after 'Microsoft.CSharp.targets' for 'IntermediateOutputPath' to be defined -->
<PathMap>$(MSBuildProjectDirectory)\$(IntermediateOutputPath)=.</PathMap>
</PropertyGroup>
</Project>
Replace <PathMap> with <PathMap Condition="'$(Configuration)'=='Release'"> for the option to apply to release build(s), only.
Note: the replacement path is set to "." in the examples above because csc does not allow it to be empty (error CS8101: The pathmap option was incorrectly formatted). Any other non-empty user-defined string will work in place of . as well.

Why does overriding the Build target in msbuild work for C++ projects but fail for C# projects?

I am overriding the Build target like this in my file OverrideBuild.targets:
<Target Name="OriginalBuild" DependsOnTargets="$(BuildDependsOn)">
<Message Text="Finished running target OriginalBuild" Importance="High" />
</Target>
<Target Name="Build" >
<CheckArtifacts ProjectGuid = "$(ProjectGuid)" SolutionPath = "$(SolutionPath)" >
<Output PropertyName = "ArtifactsHaveChanged" TaskParameter = "Result" />
</CheckArtifacts>
<Message Text="ArtifactsHaveChanged = $(ArtifactsHaveChanged)" Importance="high" />
<!-- if the artifacts.props file has not just been updated then we can run the original build target -->
<Message Condition="'$(ArtifactsHaveChanged)' == 'false'" Text="Running target OriginalBuild" Importance="High" />
<CallTarget Condition="'$(ArtifactsHaveChanged)' == 'false'" Targets="OriginalBuild" />
<!-- Otherwise we need to run a new msbuild to avoid using an out-of-date cached version of the artifacts.props file.
To force the msbuild process not to use the cached values from this process we must pass at least one property.
-->
<Message Condition="'$(ArtifactsHaveChanged)' == 'true'" Text="Running target OriginalBuild in nested msbuild" Importance="High" />
<MSBuild Condition="'$(ArtifactsHaveChanged)' == 'true'" Targets="OriginalBuild"
Projects="$(MSBuildProjectFullPath)" Properties="InNestedMsbuild=true" />
<!-- Visual Studio doesn't pick up on the modified artifacts.props file unless we force it to reload the solution -->
<Touch Condition="'$(ArtifactsHaveChanged)' == 'true' and '$(BuildingInsideVisualStudio)' == 'true'" Files = "$(SolutionPath)" />
<Message Text="Finished running build target override" Importance="High" />
</Target>
and each of my .vcxproj or .csproj files includes this file at the end:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\OverrideBuild.targets" />
</Project>
This works as I want it to for the C++ projects but fails with the C# projects. When building a C# project via msbuild it fails because the command line to the C# compiler is missing reference arguments for local assemblies. For example, a C# file that has a line like this at the top of the file:
using My.Utils.Common;
fails with the following error message:
error CS0234: The type or namespace name 'Common' does not exist in the namespace 'My.Utils' (are you missing an assembly reference?)
And looking at the compiler command used it is missing this line:
/reference:C:\Code\scratch\Build\My.Utils.Common\Bin\Release\My.Utils.Common.dll
That missing line is present when I comment out my override of the Build target. And weirdly enough it will build fine from within Visual Studio even with my Build override in place. It only fails when building using msbuild from the command line and only for C# projects.
I thought that the way I had overriden the Build target would be completely transparent but apparently it isn't. Can anybody shed some light on what is going wrong ?
It seems that when project A depends on project B with a project reference, the outputs of the Build target of B are used to deduce what should be passed as a reference to the compiler when building A. This is presumably somewhere in the ResolveAssemblyReferences logic.
Therefore to get your replacement Build target working, you need to make its outputs match those of the standard Build.
Here is how you can achieve this:
<Target
Name="Build"
Condition=" '$(_InvalidConfigurationWarning)' != 'true' "
DependsOnTargets="GetTargetPathWithTargetPlatformMoniker"
Returns="#(TargetPathWithTargetPlatformMoniker)" >
</Target>
Here Returns="#(TargetPathWithTargetPlatformMoniker)" is what the Returns of the standard Build in the SDK is. But the item array #(TargetPathWithTargetPlatformMoniker) is initially empty, so you need to run the Target GetTargetPathWithTargetPlatformMoniker to populate it before hand.
These are implementation details of the build system, so they may vary by SDK version, but you can always inspect the logic in C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.target or equivalent.
Note that this cannot be used directly with C++ projects, their default Build target is a bit different. You may need to vary by the project type to support both. The Condition on a Target does not stop it from overwriting the existing one, it only stops it from executing, so if you need a target overwrite to differ, you need to put the alternatives in files and import them conditionally. I don't know of a more convenient way, but that at least works.
Why does overriding the Build target in msbuild work for C++ projects but fail for C# projects?
After test your sample, I found the error not comes from the overriden the Build target, it should be related to the project type which you referenced.
Because I have tried comment the import line in the HelloWorld project file:
<Import Project="..\..\OverrideBuild.targets" />
Then MSBuild command line still throw that error.
Besides, I found your referenced project HelloWorldHelper is a Console application project, which output type is Class library.
To resolve this issue, I have created a new Class library instead of Console application, then build it from MSBuild command line, it works fine.
So, please try to convert your referenced project to Class library.
Hope this helps.

Why does the selected build configuration not get applied to the project file?

This may be a noobish question but here I go anyway.
So in VS I have a project whose build configuration I changed from Debug|AnyCpu to Release|AnyCpu.
Now this all works good and fine and when I build the project via VS this configuration is also used in the build process.
however I am also using the msbuild.exe in order to build the project via command sometimes and the problem is no matter what I do I can not change the
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
element of the project via VS. So setting the build configuration does only seem to work for VS and I bascially have to manually add this in the project file so that the msbuild.exe uses the correct build configuration.
Any Idea how I can change it in VS so the change also alters the project file ?
You don't need to change it explicitly. This string is "default configuration" for msbuild and VS - if no $(Configuration) value specified - set it to Debug.
If you want to build release configuration using msbuild you may want to specify configuration property or platform architecture in command line explicitly:
msbuild.exe myProject.csproj /p:Configuration="Release" /p:Platform="Any CPU"

Specifying project Property values from within Visual Studio

If I have properties defined in my project file like so
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<foo>bar</foo>
</PropertyGroup>
</Project>
I can easily set these properties on the MSBuild command line using /p:foo=newValue.
Is there a way of specifying the property value within the Visual studio (2010) GUI? I have had a look but could not find anything within the project properties pages.
Are you looking for conditional compilation symbols?
In VS2010:
Go to the project properties
Go to the Build tab
Under General you will see a place to define "Conditional compilation symbols".
You can enter "foo=bar" there, and you will get this in your .csproj file:
<Project ...>
<PropertyGroup ...>
<DefineConstants>Foo=bar</DefineConstants>
</PropertyGroup>
</Project>
I found this question when looking for an answer to the same thing: I can easily use /p or environment variables to control things when calling MSBuild on the command line, but how do you do similar in the IDE?
My solution was to add a “user” properties file. That is
<!-- Running from the IDE, you can't simply set properties via /p or environment variables.
So, this local file is read if it exists. It is not checked in to version control; but can contain
settings to be used for your immediate work.
If you make a settings.props.user file, remember DO NOT check it in!
-->
<ImportGroup>
<Import
Condition="exists('$(MSBuildThisFileDirectory)settings.props.user')"
Project="$(MSBuildThisFileDirectory)settings.props.user" />
</ImportGroup>
I can now edit some properties in the file settings.props.user conveniently located in the same directory, and not worry about accidentally checking in funny settings. Even when building in the IDE, it reads the text file anew when building. So, just keep the props.user file open in a text editor and it's handy enough to change on the fly, without an IDE extension.

Automate VS 2010 "Publish" Config File Substitutions

I'm using the config file replacement feature of Visual Studio 2010's "Publish" functionality, as described in this article. I want to automate this using MSBuild/Hudson. Does anybody know how to do this?
I like how it works but if I cannot automate it I'll have to switch to XmlMassUpdate or similar.
Explanation
To transform your config file you'll have to execute the TransformWebConfig target.
This target takes two files Web.config and Web.$(Configuration).config and generates a Web.config. The generated file is the transformed version of the original one for the current configuration.
This file is generated in folder : obj\$(Configuration)\TransformWebConfig
Usage
You don't really explain what you want to achieve, so here a basic usage, a job that generates a transformed config file in a given folder.
Add the following piece in the end of your project file *.csproj after the import of Microsoft.WebApplication.targets
<PropertyGroup>
<!-- Directory where your web.config will be copied -->
<TransformedWebConfigDestination>$(MSBuildProjectDirectory)</TransformedWebConfigDestination>
</PropertyGroup>
<!--
This target transforms the web.config based on current configuration and
put the transformed files in $(TransformedWebConfigDestination) folder
-->
<Target Name="ConfigSubstitution">
<CallTarget Targets="TransformWebConfig"/>
<ItemGroup>
<TransformedWebConfig Include="obj\$(Configuration)\TransformWebConfig\Web.config"/>
</ItemGroup>
<!-- Copy the transformed web.config to the configured destination -->
<Copy SourceFiles="#(TransformedWebConfig)"
DestinationFolder="$(TransformedWebConfigDestination)"/>
</Target>
In Hudson you could add a Build step in your build, or create a dedicated job configured as follow:
MsBuild Build File : Your csproj file.
Command Line Arguments : /t:ConfigSubstitution /p:Platform=AnyCpu;Configuration=Test;TransformedWebConfigDestination=DestinationFolder
Edit your web project.csproj
under
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
Add -
<UseMsDeployExe>True</UseMsDeployExe>
Look at the Build output (make sure VS Tools - Options - Project & Solutions -Build & Run - MSBuild Output Verbosity - Detailed)
You should be able to see the msdeploy commands VS uses to produce the package. It's my understanding that VS actually uses Web Platform Pipeline API's and .target files to actually produce the deploy packages when building using MSBuild, and this command changes to use MsDeploy instead.
This stuff is so in need of documentation, its very frustrating.
I am using this in Hudson to target Release:
/Property:Configuration=Release
The exact settings are:
Build
MSBuild Version: msbuild-4 (configured to point to v4 msbuild)
MsBuild Build File: project_name.sln
Command Line Arguments: /Property:Configuration=Release
You can test this in your project directory by running something similar (as your .NET framework version may differ) to this:
%SYSTEMROOT%\Microsoft.NET\Framework\v4.0.30319\msbuild project.sln /Property:Configuration=Release

Resources