I've created my own targets file which during the build process runs a custom tool generates some C# code which are then included in the .csproj.
I have something very like this.
<Project Sdk="Microsoft.NET.Sdk" InitialTargets="MyTarget">
.....
<Import Project="MyTargetsFile.targets" />
<ItemGroup>
<XYZ Include="**\*.xyz" />
</ItemGroup>
</Project>
The problem I encounter if that if I change the .xyz visual studio does trigger a rebuild because it considers it up to date. On the other hand if i run msbuild Systems.csproj /v:diag > Build.log it detects the changes and it rebuilds the project.
After a bit more research I've reached the conclusion that VS doesn't not even trigger MSBuild in this case. Is seems to me that visual studio just checks just .cs files for changes and ignores the rest.
Now my question is how do I make VS trigger msbuild if I've made a change in my .xyz file?
I'm using Visual Studio Enterprise 2017 Version 15.6.6
Update
I know I can set the build action for the files to Compile but they contain .xml and that causes an error.
I also know that I can clean the project and build, but I'm interested in an incremental build not a full one.
After a lot of googling I've been able to find a solution, not necessarily the best, but it seems to do the job.
As stated in the question my problem was the vs was not triggering msbuild. Looks like in order to let msbuild always run (this does not mean that you get a full build eveytime, it just means you let msbuild decide what to do and not vs) you have to add
<PropertyGroup>
<DisableFastUpToDateCheck>True</DisableFastUpToDateCheck>
</PropertyGroup>
MSDN says the following about DisableFastUpToDateCheck:
A boolean value that applies to Visual Studio only. The Visual Studio
build manager uses a process called FastUpToDateCheck to determine
whether a project must be rebuilt to be up to date. This process is
faster than using MSBuild to determine this. Setting the
DisableFastUpToDateCheck property to true lets you bypass the Visual
Studio build manager and force it to use MSBuild to determine whether
the project is up to date.
Another way to solve it although I'm not sure it's suitable for everyone, it to set the build action to Embedded resource.
Visual studio doesn't trigger MSBuild
Do you mean Visual studio doesn't trigger MSBuild if you change the .xyz?
It depends on the Build Action of your .xyz file. If you set the Build Action of that file to C# compiler, when you change the content of that file, VS/MSBuild will compile this file to check the content of this file. If it was changed, it will considers it not up to date, then trigger MSBuild.
The default build action of .cs file is C# compiler, most the default build action of the rest files should be None. When we add a file with build action None, VS/MSBuild will not check the content of this file, only check the input and the output of this file. That the reason why Visual studio doesn't trigger MSBuild if you change the .xyz.
For example, when we add a text file in the Visual Studio with build action None, build the project. Then I change some content in the text file, build again the project, it doesn't trigger MSBuild.
If we want to the MSBuild was triggered after we change the text file, we recommend to clean the build to remove the output, then when we build it again, MSBuild will be triggered.
Then I change the build action of the file to C# compiler(To avoid introducing compilation errors, I use space instead of code in this file.), I change the text file with a space after this project is up to date, build the project again, Visual studio trigger MSBuild.
Hope this helps.
Related
I have a file structure like the following:
- binaries
- binary1.dll
- dev
- <developer-name>
- a.csproj
-trunk
- a.csproj
Developers who need to work on a.csproj will create a branch in dev and they will work from there. Our projects need to have a reference to binary1.dll in the binaries directory.
If the reference is a relative path (the Visual Studio default) then the path will not work both for the project in trunk and the project in the developer's branch.
To work around this problem I thought of creating an environment variable and using that in the project file instead:
<Reference Include="binary1">
<HintPath>$(MY_ENV_VAR)\binary1.dll</HintPath>
</Reference>
This works perfectly, but I wanted to help developers add references more easily, so I wrote a program that will convert relative paths that point to binary1.dll (for example, from the dev branch a.csproj it would change the path ../../binaries/binary1.dll to $(MY_ENV_VAR)\binary1.dll) but I have not figured out how to get that to work.
If I use a pre-build event, the project is already loaded into memory and the event return an error because it cannot write the project file.
Then I realized that I could override MSBuild targets, and attempted with the targets: BeforeCompiler, AfterCompiler, BeforeBuild, AfterBuild and in all of them the project is already locked.
Then I ran into this answer and I modified my code to call the executable in the GenerateApplicationManifest target, but that one doesn't seem to call the executable at all.
Some other ideas that I have been playing with are creating a new project that does the updating of the second project and have a link between them, but that would duplicate the number of projects.
I could also just change the depth of trunk, but that only hides the problem and doesn't really solve it. When developers create a branch inside their dev branch to work on different features or bugs then I have the same problem all over again.
There might also be another feature which fixes this in a more elegant way, but I haven't been able to find anything.
So my question: How do I get MS Build or pre-build events to modify a CS project?
I found a way to do this. The issue was that the Visual Studio process itself was locking the project, but Visual Studio could overwrite the file. I ended up modifying a.csproj to include:
<Target Name="BeforeBuild">
<Exec Command="UpdateReferences.exe" /> <!-- This creates the $(ProjectPath).new file -->
<Move SourceFiles="$(ProjectPath).new" DestinationFiles="$(ProjectPath)" />
</Target>
All I want to do is assign a project property with a value parsed from an external file when building from Visual Studio 2010. Specifically, I want to populate the HelpFileVersion in a Sandcastle Help File Builder project (see my thread here for specifics).
When building from VS, properties are only evaluated when the project is loaded, thus I thought I could just re-evaluate this property at build time in an MSBuild task, like this (in my shfbproj):
<Target Name="BeforeBuildHelp">
<PropertyGroup>
<HelpFileVersion>{#Major}.{#Minor}.{#Build}.{#Revision}</HelpFileVersion>
<In>$([System.IO.File]::ReadAllText('$(MSBuildProjectDirectory)\..\SolutionInfo.cs'))</In>
<Pattern>^\s*\[assembly: AssemblyVersion\(\D*(\d+)\.(\d+)\.(\d+).(\d+)</Pattern>
<Major>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups[1].Value)</Major>
<Minor>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups[2].Value)</Minor>
<Build>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups[3].Value)</Build>
<Revision>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups[4].Value)</Revision>
</PropertyGroup>
<Message Importance="High" Text="HelpFileVersion: $(Major).$(Minor).$(Build).$(Revision)" />
</Target>
This works just fine when building from MSBuild or command line directly, but if I update the external file in VS, the updated version (as set in the MSBuild task above) does not make it back to the IDE's instance of the HelpFileVersion property until I reload the project (which has not been working out very well for me to remember to do). I know my Major, Minor, Build, and Revision properties are updating correctly (seen by the message task). In my other thread listed above, the author of the SHFB tool mentioned that:
"As far as I know Visual Studio only edits project properties found at the project's root level and won't see any within a separate build task such as BeforeBuildHelp."
So, my question is, do any of you know a way, building from Visual Studio 2010, for me to update an IDE's instance of a property at build time from an MSBuild task or otherwise? I have tried setting the property several ways (CreateProperty, PropertyGroup, using DependsOn attribute, using CallTarget, etc), and every time I can get the correct value within the task, but the value is always stale in the IDE's property (seen by echoing it from a PostBuildEvent).
See:
https://jessehouwing.net/visual-studio-msbuild-just-in-time-file-changes/
Visual Studio actually keeps the files that make up your solution in memory to improve its performance. MsBuild will actually detect that it's running inside Visual Studio and will grab the files from the in-memory cache instead of grabbing them from disk.
The problem is that any changes made to files in the solution during the build aren't picked up by MsBuild until the next time you build your project. The inner workings are explained in this post in the MSDN forums.
See:
http://social.msdn.microsoft.com/forums/en-US/msbuild/thread/14bb304d-d8e6-4227-bc2b-e2e6d4f979be
In our case we decided to make MsBuild use the on-disk files by setting the "UseHostCompilerIfAvailable" property to 'false' in the first propertygroup of the project file we were trying to patch on the fly.
See:
https://stackoverflow.com/a/1485062/736079
I have inherited a C# solution where the projects have a configured "Post-build command line". In this command line, there are a couple of user-defined property sheet macros that copy various output files to specific folders. However, when I build any of the projects, the macros are incorrectly defined as empty strings.
E.g.
copy "$(TargetPath)" "$(PluginPath)\$(ConfigurationName)"
The standard macros, e.g. $(TargetPath), work great, but I can't see any way of controlling the value of the user-defined macros. In the post-build step there is a "Macros >>" button which shows the standard macros, but there's no way that I can see to either to edit their values or add new, user defined macros.
It looks like the previous developer had this working, so what am I missing?
I have read that macros can be defined in .vsprops files, but only Visual C++ projects support these files. When I look in the Property Manager window, I see only the message "No Visual C++ project is loaded". (I'd expect that user-defined property sheet macros would be equally as useful in the "Post-build command line" of C++ projects as they are in C# or projects in any language.)
With a quick search I found this, it might help.
Update:
After adding the following to my .csproj project file, I can use the PluginPath as a macro in the post-build command line with copy "$(TargetPath)" "$(PluginPath)\$(ConfigurationName)" (tested in Visual Studio 2008)
...
<PluginPath>C:\apps\</PluginPath>
</PropertyGroup>
You can follow any solution as described below.
Create batch file and insert following code
set MY_INCLUDES_DIR=D:\MyIncludes
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools\vsvars32.bat"
"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" D:\MySolution.sln
Start Visual studio solution by double clicking this file. Advantage of this solution is all projects can use same environment variable.
Define following xml tag in visual studio project file.
<PropertyGroup>
<MY_INCLUDES_DIR>D:\MyIncludes\</MY_INCLUDES_DIR>
</PropertyGroup>
Create system environment variable named MY_INCLUDES_DIR and simply use $(MY_INCLUDES_DIR) in visual studio.
I have a c# .Net 4.0 project created with VS2010 and now being accessed with VS2012.
I'm trying to publish only the needed files from this website to a destination location (C:\builds\MyProject[Files])
My file structure:
./ProjectRoot/MyProject.csproj
./ProjectRoot/Properties/PublishProfiles/FileSystemDebug.pubxml
I'm running the following via MSBuild:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe ./ProjectRoot/MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=./ProjectRoot/Properties/PublishProfiles/FileSystemDebug.pubxml
Here's the xml in FileSystemDebug.pubxml
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>FileSystem</WebPublishMethod>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<ExcludeApp_Data>False</ExcludeApp_Data>
<publishUrl>C:\builds\MyProject\</publishUrl>
<DeleteExistingFiles>True</DeleteExistingFiles>
</PropertyGroup>
</Project>
The resulting behavior is:
a zip file is created here:./ProjectRoot/obj/Debug/Package/MyProject.zip
Nothing is deployed to <publishUrl>C:\builds\MyProject\</publishUrl> WTF
the zip file that is created is a pigs breakfast and full of files that aren't needed for the application.
When I run this publish profile through visual studio a folder is created at *C:\builds\MyProject* and contains the exact artifacts that I want.
How do I get this simple result from msbuild?
FYI: I had the same issue with Visual Studio 2015. After many of hours trying, I can now do msbuild myproject.csproj /p:DeployOnBuild=true /p:PublishProfile=myprofile.
I had to edit my .csproj file to get it working. It contained a line like this:
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets"
Condition="false" />
I changed this line as follows:
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v14.0\WebApplications\Microsoft.WebApplication.targets" />
(I changed 10.0 to 14.0, not sure whether this was necessary. But I definitely had to remove the condition part.)
Found the answer here:
http://www.digitallycreated.net/Blog/59/locally-publishing-a-vs2010-asp.net-web-application-using-msbuild
Visual Studio 2010 has great new Web Application Project publishing
features that allow you to easy publish your web app project with a
click of a button. Behind the scenes the Web.config transformation and
package building is done by a massive MSBuild script that’s imported
into your project file (found at: C:\Program Files
(x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets).
Unfortunately, the script is hugely complicated, messy and
undocumented (other then some oft-badly spelled and mostly useless
comments in the file). A big flowchart of that file and some
documentation about how to hook into it would be nice, but seems to be
sadly lacking (or at least I can’t find it).
Unfortunately, this means performing publishing via the command line
is much more opaque than it needs to be. I was surprised by the lack
of documentation in this area, because these days many shops use a
continuous integration server and some even do automated deployment
(which the VS2010 publishing features could help a lot with), so I
would have thought that enabling this (easily!) would be have been a
fairly main requirement for the feature.
Anyway, after digging through the Microsoft.Web.Publishing.targets
file for hours and banging my head against the trial and error wall,
I’ve managed to figure out how Visual Studio seems to perform its
magic one click “Publish to File System” and “Build Deployment
Package” features. I’ll be getting into a bit of MSBuild scripting, so
if you’re not familiar with MSBuild I suggest you check out this crash
course MSDN page.
Publish to File System
The VS2010 Publish To File System Dialog Publish to File System took
me a while to nut out because I expected some sensible use of MSBuild
to be occurring. Instead, VS2010 does something quite weird: it calls
on MSBuild to perform a sort of half-deploy that prepares the web
app’s files in your project’s obj folder, then it seems to do a manual
copy of those files (ie. outside of MSBuild) into your target publish
folder. This is really whack behaviour because MSBuild is designed to
copy files around (and other build-related things), so it’d make sense
if the whole process was just one MSBuild target that VS2010 called
on, not a target then a manual copy.
This means that doing this via MSBuild on the command-line isn’t as
simple as invoking your project file with a particular target and
setting some properties. You’ll need to do what VS2010 ought to have
done: create a target yourself that performs the half-deploy then
copies the results to the target folder. To edit your project file,
right click on the project in VS2010 and click Unload Project, then
right click again and click Edit. Scroll down until you find the
Import element that imports the web application targets
(Microsoft.WebApplication.targets; this file itself imports the
Microsoft.Web.Publishing.targets file mentioned earlier). Underneath
this line we’ll add our new target, called PublishToFileSystem:
<Target Name="PublishToFileSystem"
DependsOnTargets="PipelinePreDeployCopyAllFilesToOneFolder">
<Error Condition="'$(PublishDestination)'==''"
Text="The PublishDestination property must be set to the intended publishing destination." />
<MakeDir Condition="!Exists($(PublishDestination))"
Directories="$(PublishDestination)" />
<ItemGroup>
<PublishFiles Include="$(_PackageTempDir)\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(PublishFiles)"
DestinationFiles="#(PublishFiles->'$(PublishDestination)\%(RecursiveDir)%(Filename)%(Extension)')"
SkipUnchangedFiles="True" />
</Target>
This target depends on the
PipelinePreDeployCopyAllFilesToOneFolder target, which is what VS2010
calls before it does its manual copy. Some digging around in
Microsoft.Web.Publishing.targets shows that calling this target causes
the project files to be placed into the directory specified by the
property _PackageTempDir.
The first task we call in our target is the Error task, upon which
we’ve placed a condition that ensures that the task only happens if
the PublishDestination property hasn’t been set. This will catch you
and error out the build in case you’ve forgotten to specify the
PublishDestination property. We then call the MakeDir task to create
that PublishDestination directory if it doesn’t already exist.
We then define an Item called PublishFiles that represents all the
files found under the _PackageTempDir folder. The Copy task is then
called which copies all those files to the Publish Destination folder.
The DestinationFiles attribute on the Copy element is a bit complex;
it performs a transform of the items and converts their paths to new
paths rooted at the PublishDestination folder (check out Well-Known
Item Metadata to see what those %()s mean).
To call this target from the command-line we can now simply perform
this command (obviously changing the project file name and properties
to suit you):
msbuild Website.csproj "/p:Platform=AnyCPU;Configuration=Release;PublishDestination=F:\Temp\Publish" /t:PublishToFileSystem
Still had trouble after trying all of the answers above (I use Visual Studio 2013). Nothing was copied to the publish folder.
The catch was that if I run MSBuild with an individual project instead of a solution, I have to put an additional parameter that specifies Visual Studio version:
/p:VisualStudioVersion=12.0
12.0 is for VS2013, replace with the version you use. Once I added this parameter, it just worked.
The complete command line looks like this:
MSBuild C:\PathToMyProject\MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=MyPublishProfile /p:VisualStudioVersion=12.0
I've found it here:
http://www.asp.net/mvc/overview/deployment/visual-studio-web-deployment/command-line-deployment
They state:
If you specify an individual project instead of a solution, you have to add a parameter that specifies the Visual Studio version.
It looks to me like your publish profile is not being used, and doing some default packaging. The Microsoft Web Publish targets do all what you are doing above, it selects the correct targets based on the config.
I got mine to work no problem from TeamCity MSBuild step, but I did specify an explicit path to the profile, you just have to call it by name with no .pubxml (e.g. FileSystemDebug). It will be found so long as in the standard folder, which yours is.
Example:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe ./ProjectRoot/MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=FileSystemDebug
Note this was done using the Visual Studio 2012 versions of the Microsoft Web Publish targets, normally located at "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web". Check out the deploy folder for the specific deployment types targets that are used
Actually I merged all your answers to my own solution how to solve the above problem:
I create the pubxml file according my needs
Then I copy all the parameters from pubxml file to my own list of parameters "/p:foo=bar" for msbuild.exe
I throw away the pubxml file
The result is like that:
msbuild /t:restore /t:build /p:WebPublishMethod=FileSystem /p:publishUrl=C:\builds\MyProject\ /p:DeleteExistingFiles=True /p:LastUsedPlatform="Any CPU" /p:Configuration=Release
FYI: Same problem with running on a build server (Jenkins with msbuild 15 installed, driven from VS 2017 on a .NET Core 2.1 web project).
In my case it was the use of the "publish" target with msbuild that ignored the profile.
So my msbuild command started with:
msbuild /t:restore;build;publish
This correctly triggerred the publish process, but no combination or variation of "/p:PublishProfile=FolderProfile" ever worked to select the profile I wanted to use ("FolderProfile").
When I stopped using the publish target:
msbuild /t:restore;build /p:DeployOnBuild=true /p:PublishProfile=FolderProfile
I (foolishly) thought that it would make no difference, but as soon as I used the DeployOnBuild switch it correctly picked up the profile.
First check the Visual studio version of the developer PC which can publish the solution(project).
as shown is for VS 2013
/p:VisualStudioVersion=12.0
add the above command line to specify what kind of a visual studio version should build the project. As previous answers, this might happen when we are trying to publish only one project, not the whole solution.
So the complete code would be something like this
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe" "C:\Program Files (x86)\Jenkins\workspace\Jenkinssecondsample\MVCSampleJenkins\MVCSampleJenkins.csproj" /T:Build;Package /p:Configuration=DEBUG /p:OutputPath="obj\DEBUG" /p:DeployIisAppPath="Default Web Site/jenkinsdemoapp" /p:VisualStudioVersion=12.0
Run from the project folder
msbuild /p:DeployOnBuild=true /p:PublishProfile="release-file.pubxml" /p:AspnetMergePath="C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" /p:Configuration=Release
This takes care of web.config Transform and AspnetMergePath
I downloaded and installed TypeScript extension for VS 2012, I got my first sample compiles by manually dragging the ts file onto the tsc.exe file! because no other way to compile the file will work.
I don't want to manually do this everytime I want to debug a page! I have read about 5 articles on the web and none of the solutions work. I've tried adding TypeScript compiler to PATH in Windows, I've tried downloading and installing via Nuget Package Manager the Sholo thing, I've tried these pages:
Using TypeScript in cshtml files
Visual Studio TypeScript Options
Debugging TypeScript code with Visual Studio
Cannot compile typescript using tsc node module
TypeScript - Visual Studio - d3
Visual Studio 2012 TypeScript project ignoring two files during compile
TypeScript / Visual Studio 2012 / Compilation parameters
Using TypeScript in an existing Visual Studio Web Site project
Visual Studio TypeScript Options
Compile generated files in Visual Studio
And not a single solution has worked.
I have even downloaded and installed the Web Essentials plugin for Visual Studio and gone to Options menu, then selected "Compile all TypeScript files on Build = True" and "Compile TypeScript on Save = True" - but nothing works.
I've read the entire TypeScript website, the specification, and even their discussion tab on the codeplex site.
How can I get TypeScript to compile when I save changes to the .ts file or when I press F5/Debug/Build?
*I don't really want any third-party scripts/plugins, etc unless it's absolutely necessary. I've seen a couple of them and it's just ... there's no point. I might as well just write pure JavaScript.
You have to ensure that the BuildAction must be TypeScriptCompile for your .ts files.
I've added these lines to end of the (.csproj) project file. (Before closing Project tag)
And It seems working.
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<TypeScriptTarget>ES3</TypeScriptTarget>
<TypeScriptIncludeComments>true</TypeScriptIncludeComments>
<TypeScriptSourceMap>true</TypeScriptSourceMap>
<TypeScriptModuleKind>AMD</TypeScriptModuleKind>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<TypeScriptTarget>ES3</TypeScriptTarget>
<TypeScriptIncludeComments>false</TypeScriptIncludeComments>
<TypeScriptSourceMap>false</TypeScriptSourceMap>
<TypeScriptModuleKind>AMD</TypeScriptModuleKind>
</PropertyGroup>
<Import Project="$(VSToolsPath)\TypeScript\Microsoft.TypeScript.targets" />
I had a similar problem when I renamed my .js files to .ts. You have to right click and add a new TypeScript File to your project in order for your .csproj to recognize that the TypeScript compiler should be used on this .ts file.
You will know it is correct when you see the arrow to expand the .ts file.
If you change a .js file into a .ts file, you can go to the properties panel in Visual Studio and change the Build Action to TypeScriptCompile. This is what is missing when you change a file. This can save you from deleting and re-adding files.
I had the same problem. I couldn't add new .ts file to the project. After renaming from .js to .ts file was not compiled. It even was not compiled using tsc in command line.
BUT! After recreating the file in windows explorer it was compiled successfully. And after manually creating file in windows explorer (not Visual Studio) in Scripts folder and including it to the project - all WORKS. I couldn't detect changes between these two files. But if you create text file in explorer, rename it to .ts and after that include in project and set file's Build Action to TypeScriptCompile - it works.
plug
I create a NuGet package that adds a afterbuild target to your project so all the included ts files are compiled to js.
Install-Package TypeScript.Compile
I had the same problem. I updated web essentials extention and problem is solved. If you have web essentials extention, you can try that.
Please check if you have invalid TypeScript. There are some TypeScript errors that don't show up in the Error List, but they prevent TypeScript Compile-On-Save and show a Output generation failed message in the Visual Studio status bar.
These are the TypeScript errors that can cause this:
exporting a class which is not inside of a module (v 0.9.5).
Please let me know if there are more such errors, I'll add them here.