dll.refresh with devenv vs msbuild (Website Project, not application) - visual-studio

I am creating a CI server for our application(s) and have run into an issue with msbuild for our Website Project. It builds off a solution, but no proj file (as it is not a website application and cannot be). MSBuild won't pull in the dll.refresh files into the bin folder. (Not specific to a CI issue, but that's the goal) If I run it against devenv.com (CLI attempts) to build then it does pull in the dll.refresh and appears to work just fine.
From what I can find on MsBuild logs, it appears the the Copy task (which is just the default rule from msbuild itself) doesn't target the /bin folder when looking for the DLL files, but the root of the solution (/www in this case).
Just looking for some more information, as all other research points have seeming run dry at this point. (Does it have to be Msbuild? No, but I would like to make the CI configuration very simple for anyone else to re-produce and a custom build script/batch file and VS install on the CI server would make it much more complex).
Thanks.

I cannot reproduce the behavior you describe using VS2013 / MSBuild 12.0.31101.0.
Repro:
Create new website in VS
Add Reference to assembly on disk
Clean the bin directory of all files except *.refresh
Save all
Run msbuild WebsiteSolution.sln
Result: DLLs referenced in the *.refresh are re-created.
A read-through of the generated MSBuild file shows that the paths in the *.refresh files are resolved relative to the base directory of the website. I will note that this only occurs on the Build target, so I don't know what you mean when you say "the Copy task [...] is the default rule". Perhaps you are using some custom MSBuild target which needs to include the default target?
The relevant parts of the generated MSBuild (produced with MSBuildEmitSolution=1):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<!-- Edit: Snipped -->
<!-- The website location is stored relative to the .sln -->
<!-- (which is the same as the location of the temporary msbuild file) -->
<Project_[...]_AspNetPhysicalPath>..\..\WebSites\WebSite1\</Project_[...]_AspNetPhysicalPath>
<!-- Edit: Snipped -->
</PropertyGroup>
<ItemDefinitionGroup />
<!-- Edit: Snipped -->
<Target Name="Build" Condition=" ('$(CurrentSolutionConfigurationContents)' != '') and (false or ( ('$(Configuration)' == 'Debug') and ('$(Platform)' == 'Any CPU') ) or ( ('$(Configuration)' == 'Release') and ('$(Platform)' == 'Any CPU') )) " DependsOnTargets="GetFrameworkPathAndRedistList">
<!-- Edit: Snipped -->
<!-- *.refresh items are discovered and saved in [...]_References_RefreshFile -->
<CreateItem Include="$(Project_[...]_AspNetPhysicalPath)\Bin\*.refresh">
<Output TaskParameter="Include" ItemName="Project_[...]_References_RefreshFile" />
</CreateItem>
<!-- The contents of the *.refresh are read to [...]_References_ReferenceRelPath -->
<ReadLinesFromFile Condition=" '%(Project_[...]_References_RefreshFile.Identity)' != '' " File="%(Project_[...]_References_RefreshFile.Identity)">
<Output TaskParameter="Lines" ItemName="Project_[...]_References_ReferenceRelPath" />
</ReadLinesFromFile>
<!-- Those contents are relative to [...]_AspNetPhysicalPath -->
<CombinePath BasePath="$(Project_[...]_AspNetPhysicalPath)" Paths="#(Project_[...]_References_ReferenceRelPath)">
<Output TaskParameter="CombinedPaths" ItemName="Project_[...]_References" />
</CombinePath>
<!-- This seems to be a no-op, since you cannot copy if it doesn't exist -->
<Copy Condition="!Exists('%(Project_[...]_References.Identity)')" ContinueOnError="true" SourceFiles="#(Project_[...]_References->'%(FullPath)')" DestinationFolder="$(Project_[...]_AspNetPhysicalPath)\Bin\" />
<!-- Edit: Snipped -->
<!-- This will copy [...]_References to [...]_References_CopyLocalFiles and add references -->
<ResolveAssemblyReference Condition="Exists('%(Project_[...]_References.Identity)')" Assemblies="#(Project_[...]_References->'%(FullPath)')" TargetFrameworkDirectories="$(Project_[...]__TargetFrameworkDirectories)" FullFrameworkFolders="$(Project_[...]__FullFrameworkReferenceAssemblyPaths)" SearchPaths="{RawFileName};{TargetFrameworkDirectory};{GAC}" FindDependencies="true" FindSatellites="true" FindSerializationAssemblies="true" FindRelatedFiles="true" TargetFrameworkMoniker=".NETFramework,Version=v4.5">
<Output TaskParameter="CopyLocalFiles" ItemName="Project_[...]_References_CopyLocalFiles" />
</ResolveAssemblyReference>
<!-- [...]_References_CopyLocalFiles is copied to the bin directory -->
<Copy Condition="(false) or ('$(AspNetConfiguration)' == 'Debug') or ('$(AspNetConfiguration)' == 'Release')" SourceFiles="#(Project_[...]_References_CopyLocalFiles)" DestinationFiles="#(Project_[...]_References_CopyLocalFiles->'$(Project_[...]_AspNetPhysicalPath)\Bin\%(DestinationSubDirectory)%(Filename)%(Extension)')" />
<!-- Edit: Snipped -->
</Target>
<!-- Edit: Snipped -->
</Project>
I have not tried this on a machine which does not have VS installed, so it may not apply directly, but you should definitely be able to build with the generated metaproj file even without Visual Studio installed.

I had this problem as well; the problem was actually that our build configuration was neither Debug nor Release, so msbuild was actually skipping the compile (and thus the restore with *.refresh):
Skipping because the "Dev" configuration is not supported for this web
project. You can use the AspNetConfiguration property to override the
configuration used for building web projects, by adding
/p:AspNetConfiguration= to the command line. Currently web
projects only support Debug and Release configurations.

Related

Can't add images to new .NET MAUI project on Mac without getting: The name 'Resources' is reserved and cannot be used

I just started a brand new template .NET MAUI project on my Mac and I am able to build and run the startup project with no problems.
When I add any image to the "Resources/Images" folder and then try to build the project I get the error:
Error Description:
The name 'Resources' is reserved and cannot be used.
Error Path:
Resources/Images/icon_notes.png
SPECS
Visual Studio for Mac 17.4 Preview (17.4 build 2326)
I have tried cleaning and rebuilding the project but that does not help.
Steps to reproduce:
Install Visual Studio for Mac 17.4 Preview
Create new .NET MAUI project from startup template offered by the IDE
Build and run to make sure it runs properly (It will).
Add any image to the "Resources/Images" folder and then try to rebuild.
Please help me understand what is wrong here and how to fix it.
Here is my csproj file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0-android;net6.0-ios;net6.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net6.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net6.0-tizen</TargetFrameworks> -->
<OutputType>Exe</OutputType>
<RootNamespace>Notes</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Display name -->
<ApplicationTitle>Notes</ApplicationTitle>
<!-- App Identifier -->
<ApplicationId>com.companyname.notes</ApplicationId>
<ApplicationIdGuid>2cc957c4-bc4d-4867-9002-8475070561fa</ApplicationIdGuid>
<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">14.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
<!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
<!-- Images -->
<MauiImage Include="Resources\Images\*" />
<MauiFont Include="Resources\Fonts\*" />
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
</Project>
Here is the properties on the image that is causing this:
Thanks to Liqun Shen for the direction to the solution.
The issue is that when you add an image to the Resources/Images folder and check your csproj file you will see that each image is added as an ItemGroup to the csproj file. This must be some sort of bug and the solution was to manually delete these from the csproj file after which the code builds and runs properly.
I know that in my csproj file I listed about these ItemGroups for each image added wasn't showing but checking again they were there and removing them fixed my issue. I must have copied my csproj file from one of my attempts at erasing my project and retrying again and before I added the image.
<ItemGroup>
<None Remove="Resources\Images\icon_notes.png" />
</ItemGroup>
Here is the link that Liqun Shen posted that describes this:
https://github.com/dotnet/maui/issues/10531
I have the same error from new MAUI project (No Razor) on VS for Mac v17.4.4: The name 'Resources' is reserved and cannot be used.
What I did was:
Edit "ProjectName.csproj" and change all references to folder "Resources" and renamed to "ResourcesNet"
Change the folder name from "Resources" to "ResourcesNet"
Change in App.xaml all references to "Resources" to "ResourcesNet"

Difficulty using <Import> to modularize a Visual Studio project file

I'm attempting to modularize a Visual Studio project file, but it's not working. This is for Visual Studio 2008 with .Net 3.5.
Shown below, the first example works, but the second one does not. How can I make it work..?
I'm new to this topic and probably missing something. I first became aware of it while reading a 3rd-party blog, and then found it in the documentation too. I've googled for more help, but there's too much information for me to find a relevant answer.
The main project file:
...
<!-- main project file -->
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<Target Name="AfterBuild">
<Message Text="This is a message from the *.vbproj file."/> ... this works
</Target>
</Project>
...but if <Import> is used, with the same <Target> and <Message> in the imported file, it doesn't work. MSBuild seems to process everything correctly, but nothing happens...
The main project file:
...
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<Import Project="$(MSBuildProjectDirectory)\CustomBuildEvents.targets" /> ... new tag
<Target Name="AfterBuild">
<Message Text="This is a message from the *.vbproj file."/> ... this still works
</Target>
</Project>
The imported targets file:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AfterBuild">
<Message Text="Hello from the imported file." Importance ="high"/> ... doesn't work
</Target>
</Project>
And the build output, with Verbosity set to Diagnostic:
### Halfway through the output, this is the only mention of the imported file. ###
None
CustomBuildEvents.targets ... custom file
My Project\Application.myapp
My Project\Settings.settings
### And then at the end, no mention of the imported file or its message. ###
Done building target "CoreBuild" in project "MsBuildCustomTargetTester.vbproj".
Target "AfterBuild" in file "C:\Visual Studio 2008\Solutions\MsBuildCustomTargetTester\MsBuildCustomTargetTester\MsBuildCustomTargetTester.vbproj":
Task "Message"
Hello from the *.vbproj file. ... message from main file
Done executing task "Message".
Done building target "AfterBuild" in project "MsBuildCustomTargetTester.vbproj".
Target "Build" in file "c:\WINDOWS\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets":
Building target "Build" completely.
No input files were specified.
Done building target "Build" in project "MsBuildCustomTargetTester.vbproj".
Done building project "MsBuildCustomTargetTester.vbproj".
Project Performance Summary:
109 ms C:\Visual Studio 2008\Solutions\MsBuildCustomTargetTester\MsBuildCustomTargetTester\MsBuildCustomTargetTester.vbproj 1 calls
The problem with AfterBuild is that it can only be defined once. So if you import it and then later in the project file define it again, the last definition wins and becomes the only definition.
To solve this you need to use the more advanced way to register events. Given that you are using Visual Studio 2008 (WHY?!), you need to use the more advanced syntax for your custom targets files:
<Project>
<!--
Redefines the original build order, includes the standard targets and
adds your new custom target to the end of the list.
-->
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
CustomTarget
</BuildDependsOn>
</PropertyGroup>
<CustomTarget>
<!-- Imported after Build -->
<Message Text="Hello from the imported file." Importance ="high"/>
</CustomTarget>
</Project>
There are other ways to do this which were introduced in MsBuild 4 with the BeforeTargets and AfterTargets attributes on any target, but If I'm remembering correctly the above syntax should also work with the version of MsBuild that ships with Visual Studio 2008.
See also:
What is the difference between 'DependsOnTargets' and 'AfterTargets'?
https://blogs.msdn.microsoft.com/msbuild/2006/02/10/how-to-add-custom-process-at-specific-points-during-build-method-2/

MSBuild missing output files in AfterBuild when solution is cleaned

I'm sure there is something small that I'm missing. Here's the problem:
I have a solution that has multiple projects which after each build will be zipped. Here is an example of the zip creation in one project (they are pretty much identical in others):
<ItemGroup>
<CopySourceFiles Include="$(OutDir)\**\*.*" Exclude="$(OutDir)\**\*.pdb;$(OutDir)\*.mdf;$(OutDir)\*.ldf;$(OutDir)\*.vshost.*" />
</ItemGroup>
...
<Target Name="AfterBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<MakeDir Directories="$(OutDir)\..\zip_working" />
<!-- first copy the source files specified in the CorySourceFiles ItemGroup above. -->
<Copy SourceFiles="#(CopySourceFiles)" DestinationFiles="#(CopySourceFiles->'$(OutDir)\..\zip_working\%(RecursiveDir)%(Filename)%(Extension)')" />
<!-- Perform the zip by calling the UsingTask. Make sure the DestinationFiles above and the SourceDirectory below are pointing to the same place -->
<Zip SourceDirectory="$(OutDir)\..\zip_working" OutputFilename="$(OutDir)\..\zip\$(ProjectName).zip" />
<!-- Clean up. -->
<RemoveDir Directories="$(OutDir)\..\zip_working" />
</Target>
There is a final project which has links to the zipped files that it combines into a package. All appears normal, but apparently only when the bin and zip_working folders already exist. I.e. if I clean the solution, delete the bin folders and then rebuild, the final zip that is created in the "zip" folder for each project is empty...
And then the zip files have content only after I build again.
So I'm guessing that during the build process, the AfterBuild target is running before the build output files exist. Does that sound right? I trigger the builds purely from within Visual Studio.
Regardless, how can I ensure that I can run a task on build output files only after they've been created?
Applies to Visual Studio 2013 Update 5 / MSBuild 12.0
If you delete everything in OutDir and then build the project, a top-level (as in, not inside a target) ItemGroup is evaluated before the build even starts. Some info can be found here for example. In other words, before a build and with an empty OutDir $(OutDir)\**\*.* evaluates to nothing and your CopySourceFiles item is empty.
The solution is simply to move the ItemGroup inside of the AfterBuild target. It will then be evaluated after the build and hence gets a proper view on the current files in outDir.

Is there a way to add source files to visual studio project from command-line?

I want to use sublime to edit a visual studio project.
I have a custom build:
{
"cmd": ["c:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe"],
"working_dir": "${project_path:${folder:${file_path}}}/../Project"
}
But if I add new files I also need to include them in the project.
Is there a way to do this from the command line, maybe at compile-time?
I am working with opengl using c++;
I basically set up a project using one of the examples provided on the opengl website.
Then I opened the project folder in sublime text and successfully compiled it using the custom build system.
However, when I add NEW source files to the project (*.h and *.cpp) I get a linking error.
I get the same error when I build in visual studio.
The error disappeared after I had included the files by manually browsing and adding them to the project.
What I wanted was a way to automatically add all the source files in a folder to the project(via command line, or wildcard or smth else).
This way I can easily work on a vs2010 project in sublime, add new source files and build the project.
Or maybe there already is a better workflow for this?
You could try to modify your .vcxproj file to include any .h and .cpp file in your project folder or folders below.
In case of a c++ VS project you can try to alter your .vcxproj file like this:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- rest of project file untouched -->
<!-- start of modified part -->
<ItemGroup>
<ClInclude Include="**\*.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="**\*.cpp" />
</ItemGroup>
<!-- end of modified part -->
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
Be aware that adding files to your project from inside VS at later point will replace the modification described above!
As an alternative you could also create an external project file holding the same <ItemGroup /> elements described above and include this project file into your .vcxproj.
I'll add an example of this alternative if you're interested.

Using SlowCheetah's app.config transformations with Setup projects

I'm using the SlowCheetah XML Transforms extension to handle web.config-like transformations with app.config. That part works great.
I added a setup project and configured it to include the project output of the first project. I noticed that when I ran the installer, it installed the non-transformed app.config. Looking at the Primary output Outputs (say that 10 times fast), I noticed that its finding the binary in Project\bin\Debug\Project.exe, but Project.exe.config comes from Project\app.config instead of Project\bin\Debug\Project.exe.config.
I could exclude app.config from the Primary output, and hard-code the path to a specific configuration's app.config (Project\bin\Debug\Project.exe.config), but then I'd get the same app.config regardless of which configuration I used to build it.
Is there a workaround for getting the appropriate transformed app.config in a Setup project?
Hi we are planning on releasing a new version which has ClickOnce support in the next few days. If you need a build of the add in before than which has the fix please contact me and I can get that out to you.
This may not be exactly the answer you're looking for but I have previously wrestled with how to get the correct app.config file into a setup project. I have a TFSBuild.proj msbuild file that uses transforms. The SlowCheetah transforms I think use the same msbuild task but I may be incorrect. SlowCheetah certainly provides a more useful user experience when working with transform files. My build file takes a slightly different approach. At the end of the automated build I wanted to generate installers for each of the target deployment environments. I use a number of msbuild extensions, including the TransformXml build task - not all required for the following but FWIW these are the imports:
<!-- import extensions -->
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>
I have the following environments defined:
<ItemGroup>
<!-- target deployment environments -->
<Configs Include="Prod" />
<Configs Include="Staging" />
<Configs Include="Test" />
</ItemGroup>
Then the standard AfterCompileSolution target contains a call to the target that generates the installer for each environment:
<Target Name="AfterCompileSolution">
<!-- Create installers for target deployment environments -->
<CallTarget Targets="MyProject" />
</Target>
<Target Name="MyProject" Outputs="%(Configs.Identity)">
<ItemGroup>
<MyProjectTempConfig Include="$(SolutionRoot)\MyProjectService\Temp.config" />
<MyProjectConfigFrom Include="$(SolutionRoot)\MyProjectService\App.%(Configs.Identity).config" />
<MyProjectConfigTo Include="$(SolutionRoot)\MyProjectService\App.config">
<Attributes>ReadOnly</Attributes>
</MyProjectConfigTo>
</ItemGroup>
<Message Text="MyProject - Target environment: %(Configs.Identity)" />
<!-- transform app.config using appropriate -->
<Copy SourceFiles="#(MyProjectConfigTo)"
DestinationFiles="#(MyProjectTempConfig)"
OverwriteReadOnlyFiles="true"
ContinueOnError="true"
Condition="!Exists(#(MyProjectTempConfig))"/>
<File TaskAction="RemoveAttributes" Files="#(MyProjectConfigTo)"/>
<TransformXml Source="#(MyProjectTempConfig)"
Transform="#(MyProjectConfigFrom)"
Destination="#(MyProjectConfigTo)" />
<!-- run setup -->
<Exec Command=""$(ProgramFiles)\Microsoft Visual Studio 10.0\Common7\IDE\devenv" "$(SolutionRoot)\MyProject.sln" /build Release /project MyProjectService.Setup"/>
<!-- rename output for target deployment environment -->
<Copy SourceFiles="$(SolutionRoot)\MyProjectService.Setup\Release\MyProjectService.msi"
DestinationFiles="$(OutDir)\%(Configs.Identity)_MyProjectService.msi"
OverwriteReadOnlyFiles="true"
ContinueOnError="true"/>
</Target>

Resources