I am currently using the inbuilt Publish function within VS2012 to publish an ASP.NET MVC site to a file system directory share on a Web Server. Is there anyway that I can have it publish to multiple locations rather than just the one when I click the Publish button?
I don’t want to have to create a second profile and have to do the same process twice and I have looked at modifying the pubxml file by adding in an additional tag to see if the publish routine picks it up. But unfortunately it just seems to pick up the last configuration in the list.
I know the ideal would be to implement a CI solution but for the time being my hands are tied with the Publish functionality and need to keep it relatively straight forward.
Many thanks
We had the same need of publishing our solution to multiple file share locations, and while the question was asked several months ago I thought that an answer could benefit to the community.
Since VS publish profiles are plain MSBuild files that can easily be extended, here is the solution I came with.
Note that I extracted some code fragments from our build process that is a bit more complex so I do not guarantee that it will all works without having to alter it a bit.
In the publish profile, I added a custom DeploymentPaths item as shown below.
Note that you could define one or more additional locations.
<ItemGroup Label="Defines additional publish locations">
<DeploymentPaths Include="\\SERVER1\ShareFolder\ProjectA\" />
<DeploymentPaths Include="\\SERVER2\ShareFolder\ProjectA\" />
</ItemGroup>
Then I added a custom target CustomWebFileSystemPublish to run after WebFileSystemPublish. This target calls another MSBuild file publish.xml that performs the delete of existing files and copy the new files.
<!-- Custom File System Publish to deploy to additional locations based on DeploymentPaths -->
<Target Name="CustomWebFileSystemPublish" AfterTargets="WebFileSystemPublish" Condition=" #(DeploymentPaths)!='' ">
<CreateItem Include="$(MSBuildProjectDirectory)\$(_PackageTempDir)">
<Output ItemName="AbsoluteSourcePathItem" TaskParameter="Include" />
</CreateItem>
<CreateProperty Value="%(AbsoluteSourcePathItem.Fullpath)">
<Output PropertyName="AbsoluteSourcePath" TaskParameter="Value" />
</CreateProperty>
<Message Text="### CustomWebFileSystemPublish" Importance="high" />
<Message Text="### DeploymentPaths: #(DeploymentPaths)" Importance="high" />
<MSBuild Projects="$(MSBuildProjectFile)" Properties="AbsoluteSourcePath=$(AbsoluteSourcePath)" Targets="DoPublish" />
</Target>
<Target Name="DoPublish">
<Message Text="### DoPublish $(AbsoluteOutputPath) | %(DeploymentPaths.Identity)" Importance="normal" />
<!-- Adjust path to the publish.xml file depending on where you put it in your solution -->
<MSBuild Projects="..\Deployment\publish.xml" Properties="OutputPath=$(AbsoluteSourcePath);DeployPath=%(DeploymentPaths.Identity)" />
</Target>
Finally, here is the publish.xml MSBuild file
<!-- Publish.xml -->
<Project ToolsVersion="4.0" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Start">
<PropertyGroup>
<!-- Ensure DeployPath has the expected trailing slash -->
<DeployPath Condition=" '$(DeployPath)' != '' and !HasTrailingSlash('$(DeployPath)') ">$(DeployPath)\</DeployPath>
</PropertyGroup>
<Message Text=" # Deploying from $(OutputPath) to $(DeployPath) " Importance="normal" />
</Target>
<Target Name="CleanDeployFolder" DependsOnTargets="Start"
Condition=" $(DeployPath)!=''">
<Message Text=" # Cleaning files in $(DeployPath)" Importance="normal" />
<!-- Defines the files to clean -->
<ItemGroup>
<DeployCleanFiles Include="$(DeployPath)\**\*.*" />
</ItemGroup>
<!--Delete files in Deploy folder (folders not deleted by Delete Task)-->
<Delete Files="#(DeployCleanFiles)" />
<Message Text=" # Cleaning files in $(DeployPath) Completed" Importance="normal" />
</Target>
<Target Name="CopyToDeployFolder" DependsOnTargets="CleanDeployFolder"
Condition=" $(DeployPath)!=''">
<Message Text=" # Copying files to $(DeployPath)" Importance="normal" />
<ItemGroup>
<OutputFiles Include="$(OutputPath)\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(OutputFiles)" DestinationFolder="$(DeployPath)%(OutputFiles.RecursiveDir)" />
<Message Text=" # Copying files to $(DeployPath) Completed" Importance="normal" />
</Target>
<Target Name="Default" DependsOnTargets="CopyToDeployFolder"
Condition=" $(OutputPath)!='' And $(DeployPath)!='' ">
<Message Text=" # Deploying from $(OutputPath) to $(DeployPath) Completed" Importance="normal" />
</Target>
</Project>
You could create a small Windows Service that monitors a Directory and copies to multiple locations when new files are added
Try FileSystemWatcher on MSDN
Related
Anyone knows if i could determine if AfterClean task was executed in context of Rebuild.
I am only intrested to execute my task if Clean is executed explicitly from project context menu.
<Target Name="MyTask" AfterTargets="AfterClean">
<Message Text="Removing file: cache.data" Importance="high" />
<Exec Command="del /S cache.data" ></Exec>
</Target>
found answer myself, there may be a better way.
<Target Name="BuildExecutedFlag" BeforeTargets="BeforeRebuild" >
<CreateProperty Value="1">
<Output
TaskParameter="Value"
PropertyName="WasBuildExecuted" />
</CreateProperty>
</Target>
<Target Name="MyTask" AfterTargets="AfterClean" Condition="'$(WasBuildExecuted)' != '1'">
<Message Text="Removing file: cache.data" Importance="high" />
<Exec Command="del /S cache.data" ></Exec>
</Target>
I want to copy files over to a server but before i do this i would like to include the latest msi file that i generate.
I noticed that the ItemGroup and Item have a Condition attribute but i do not know how to utilize this to include the latest file.
So far this is my setup:
<Target Name="AfterBuild">
<ItemGroup>
<Installers Include="\\SERVERNAME\BuildOutput\ProductStream\**\Installers\Customer\Installer.msi"/>
</ItemGroup>
<Message Text="FirstItem: %(Installers.Filename)" />
<Message Text="FirstItem: %(Installers.FullPath)" />
The output of this are two files:
e.g
\\Servername\BuildOutput\ProductStream\Installers\ProductStreamV2.1.1202.1402\Installer.msi
\\Servername\BuildOutput\ProductStream\Installers\ProductStreamV2.1.1405.1301\Installer.msi
I want to include the 2.1.1405.1301 build in the Item as this is the latest one.
I would appreciate if someone would assist me because i cannot find how to go about doing this from the MSDN blogs.
Thanks,
You could use a custom task for this purpose. It allows you to filter items any way you want. Here I used regular expressions to select the latest installer:
<Target Name="AfterBuild">
<ItemGroup>
<Installers Include="**\Installer.msi"/>
</ItemGroup>
<SelectLatestInstaller Installers="#(Installers)">
<Output TaskParameter="LatestInstaller" ItemName="LatestInstaller" />
</SelectLatestInstaller>
<Message Text="%(LatestInstaller.FullPath)" />
</Target>
<UsingTask TaskName="SelectLatestInstaller"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<Installers ParameterType="System.String[]" Required="true" />
<LatestInstaller ParameterType="System.String" Output="true" />
</ParameterGroup>
<Task>
<Reference Include="System.Linq" />
<Using Namespace="System" />
<Using Namespace="System.Linq" />
<Using Namespace="System.Text.RegularExpressions" />
<Code Type="Fragment" Language="cs">
<![CDATA[
LatestInstaller = Installers
.OrderByDescending(f => Regex.Match(f, #"\\ProductStreamV(?<version>(\d+.){0,3}\d+)\\").Groups["version"].Value)
.FirstOrDefault();
]]>
</Code>
</Task>
</UsingTask>
I need to tie together a bunch of steps which include building solutions, projects and running .cmd files using a custom MSBuild file.
My first pass at this is below:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>AnyCPU</Platform>
</PropertyGroup>
<ItemGroup>
<ProjectsToBuild Include="..\Hosts\solution1.sln"></ProjectsToBuild>
<ProjectsToBuild Include="..\..\solution2.sln"></ProjectsToBuild>
<ProjectsToBuild Include="helper1.csproj"></ProjectsToBuild>
<ProjectsToBuild Include="..\..\Sandboxes\helper2.sln"></ProjectsToBuild>
<Exec Include="" Command="CALL GetFiles.cmd"/>
<ProjectsToBuild Include="wix\proc\prod.wixproj"></ProjectsToBuild>
<Exec Command="CALL final.cmd"/>
</ItemGroup>
<Target Name="Build">
<MSBuild Projects="#(ProjectsToBuild)" Targets="Build">
<Output ItemName="ProjectOutputs" TaskParameter="TargetOutputs"/>
</MSBuild>
<Message Text="#ProjectOutputs"/>
</Target>
</Project>
This resulted in an error since the Exec element is in the wrong place.
Basically, I need to build solution1.sln, solution2.sln,helper1.csproj and helper2.sln (in sequence), then, run the file GetFiles.cmd, then build prod.wixproj followed by running the final.cmd file.
I have looked at MSDN (here, here, here), a blog, and browsed through various stackoverflow questions (including this, this, this, this), but none of them quite address what I am trying to do. This is the first time I have ever worked with MSBuild, so it is possible I may have missed something. Will appreciate any pointers...
Since an ItemGroup node can be a child of a Target node, break down those ItemGroup members into separate targets, then use the DefaultTargets attribute to control the sequence in which those are built.
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Target1;Target2;Target3" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5" >
<Target Name="Target1">
<Message Text="Target 1" />
</Target>
<Target Name="Target2">
<Message Text="Target 2" />
</Target>
<Target Name="Target3">
<Message Text="Target 3" />
</Target>
</Project>
The build projects are already in the correct order see:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>AnyCPU</Platform>
</PropertyGroup>
<ItemGroup>
<ProjectsToBuild Include="..\Hosts\solution1.sln"></ProjectsToBuild>
<ProjectsToBuild Include="..\..\solution2.sln"></ProjectsToBuild>
<ProjectsToBuild Include="helper1.csproj"></ProjectsToBuild>
<ProjectsToBuild Include="..\..\Sandboxes\helper2.sln"></ProjectsToBuild>
<ProjectsToBuild Include="wix\proc\prod.wixproj"></ProjectsToBuild>
</ItemGroup>
<Target Name="Build">
<Exec Command="CALL GetFiles.cmd"/>
<Message Text="Build order: %(ProjectsToBuild.Identity)"/>
<MSBuild Projects="#(ProjectsToBuild)" Targets="Build">
<Output ItemName="ProjectOutputs" TaskParameter="TargetOutputs"/>
</MSBuild>
<Message Text="#(ProjectOutputs)"/>
<<Exec Command="CALL final.cmd"/>
</Target>
</Project>
At the start the order of the itemgroup is displayed:
Project "C:\Test\Testcode\build\testcode.msbuild" on node 1 (default targets).
Build:
Build order: ..\Hosts\solution1.sln
Build order: ....\solution2.sln
Build order: helper1.csproj
Build order: ....\Sandboxes\helper2.sln
Build order: wix\proc\prod.wixproj
All done.
I'm trying to Minify Javascript and CSS using AjaxMin when I deploy using a Web Deploy Publish Profile. Here is what I have in the project file:
<Import Project="$(MSBuildExtensionsPath)\Microsoft\MicrosoftAjax\AjaxMin.tasks" />
<PropertyGroup>
<ResGenDependsOn>
MinifyJavascriptAndCss;
$(ResGenDependsOn);
</ResGenDependsOn>
</PropertyGroup>
<Target Name="MinifyJavascriptAndCss"
Condition=" '$(ConfigurationName)'=='Release' ">
<ItemGroup>
<JS Include="$(_PackageTempDir)\**\*.js"
Exclude="$(_PackageTempDir)\**\*.min.js;Scripts\*.js" />
</ItemGroup>
<ItemGroup>
<CSS
Include="$(_PackageTempDir)\**\*.css"
Exclude="$(_PackageTempDir)\**\*.min.css" />
</ItemGroup>
<Message Text="Compressing JavaScript and CSS files into $(_PackageTempDir)"
Importance="high" />
<AjaxMin JsSourceFiles="#(JS)" JsSourceExtensionPattern="\.js$"
JsTargetExtension=".min.js" CssSourceFiles="#(CSS)"
CssSourceExtensionPattern="\.css$" CssTargetExtension=".min.css" />
</Target>
If I watch the output directory I can see that the files are minified as the min.* files appear, but when the package file is deployed, they are not included.
How do I force the minified files to be included in the publish package?
It worked for me in VS2010, but does nothing with VS2012...
<!-- Use AjaxMinifier from Libs folder in this project -->
<UsingTask TaskName="AjaxMin" AssemblyFile="$(MSBuildProjectLocation)Libs\AjaxMinTask.dll" />
<!-- This target will run after publish web in Release mode -->
<Target Name="MinifyJavaScriptAndCSS" AfterTargets="CopyAllFilesToSingleFolderForPackage" Condition="'$(Configuration)'=='Release'">
<ItemGroup>
<!-- Every .js file (exclude *.min.js and *.vsdoc.js files) -->
<JS Include="$(_PackageTempDir)\**\*.js" Exclude="$(_PackageTempDir)\**\*.min.js;$(_PackageTempDir)\**\*vsdoc.js" />
<!-- Every .css file (exclude *.min.css files) -->
<CSS Include="$(_PackageTempDir)\**\*.css" Exclude="$(_PackageTempDir)\**\*.min.css" />
</ItemGroup>
<!-- Log in output build window -->
<AjaxMin JsKnownGlobalNames="jQuery,$" JsSourceFiles="#(JS)" JsSourceExtensionPattern="\.js$" JsTargetExtension=".js" CssSourceFiles="#(CSS)" CssSourceExtensionPattern="\.css$" CssTargetExtension=".css" />
<!-- Log in output build window -->
<Message Text="[pcv] $(MSBuildProjectName) -> Minified: #(JS)" Importance="high" />
<Message Text="[pcv] $(MSBuildProjectName) -> Minified: #(CSS)" Importance="high" />
</Target>
I faced the same problem and successfully resolved it. There is one easy way to do this task.
Set the Build Action of original CSS/JS files to None and set the Build Action of minify files to Content. Now when you build the project then only minified css/java script files will come.
I'm using VS2012, and this worked for me
<!--<Import Project="$(MSBuildExtensionsPath)\Microsoft\MicrosoftAjax\AjaxMin.targets" />-->
<UsingTask TaskName="AjaxMin" AssemblyFile="$(MSBuildProjectDirectory)\..\packages\AjaxMin.5.14.5506.26202\tools\net40\AjaxMinTask.dll" />
<Target Name="MinifyJsAndCss" AfterTargets="CopyAllFilesToSingleFolderForPackage" >
<ItemGroup>
<JS Include="$(_PackageTempDir)\App_Scripts\**\*.js" Exclude="$(_PackageTempDir)\**\*.min.js" />
<CSS Include="$(_PackageTempDir)\**\*.css" Exclude="$(_PackageTempDir)\**\*.min.css" />
</ItemGroup>
<Message Text="Compressing JavaScript and CSS files...(to edit this feature, unload the project, right click it ->edit -> search for 'AjaxMin' bottom of the xml)" Importance="high" />
<AjaxMin JsSourceFiles="#(JS)" JsSourceExtensionPattern="\.js$" JsTargetExtension=".js" CssSourceFiles="#(CSS)" CssSourceExtensionPattern="\.css$" CssTargetExtension=".min.css" />
</Target>
Good day.
I'm trying to deploy a web application using NAnt. It is current zipped using the NAnt ZIP task.
I can try calling MSDeploy from NAnt but I don't think MSDeploy was written for such deployments.
I can also try using NAnt task.
Does anybody have suggestions as to what approach can save me the most time?
Using the aspnet compiler is the simplest way and gets you access to all cl arguments which is not available on nant tasks. Not sure why it's so.
Here's what I do
<property name="aspnetcomplier" value="C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler.exe" />
<target name="deploy">
<mkdir dir="${output.dir}" />
<exec program="${aspnetcomplier}">
<arg value="-v" />
<arg value="/trunk" />
<arg value="-p" />
<arg value="${source.dir}\Root" />
<arg value="-f" />
<arg value="${output.dir}" />
</exec>
</target
Nothing complicated.Works like a charm.
P.S. Dont forget to do a iisreset /stop and /start
<target name="stop.iis" >
<servicecontroller action="Stop" service="w3svc" timeout="10000" verbose="true" />
</target>
<target name="start.iis" >
<servicecontroller action="Start" service="w3svc" timeout="10000" verbose="true" />
</target>