Prevent MSDeploy (selectively) from deleting folders on target IIS server - msbuild

I have an IIS web application with a structure roughly similar to:
wwww.mysite.com
file1.asp
file2.asp
\DotNet
file3.aspx
file3.aspx
We are setting up TeamCity to do auto deployments. I have an MSBuild build step that deploys to the \DotNet folder (the aspx files), and in a separate build configuration I have another MSBuild build step that deploys to the root (the asp files).
I want to allow MSDeploy to delete unnecessary files, e.g. if I remove file2.asp from VCS, I want it to delete it from the target IIS server.
However, I do NOT want it to wipe the \DotNet subfolder.
Can I get something more granular than the command line switch "SkipExtraFilesOnServer", or is this an all-or-nothing deal?

It turns out that the answer to my question was much simpler than I expected
When deploying to the root folder of an application using the MSDeployPublish target via MSBuild, by default, extra subfolders that happen to be on the filesystem of the target IIS server are deleted.
To avoid this, I simply moved the contents of my DotNet folder to a totally separate location under C:\InetPub, but retained my original virtual folder/application structure under IIS Mgr. Of course!
Now I can publish to either location as much as I please, and one won't try and delete the other because one is no longer a filesystem subfolder of the other.
If anything - this highlights how primitive our earlier folder structure was, and what a doofus I am for not realising.

I'm not exactly sure what you're looking for here. Are you trying to delete all the files from within the dotnet subfolder but keep the folder? Are you trying to have the delete operation never delete anything from the dotnet folder? The msdeploy sync operation is pretty smart. msdeploy will move all of your marked project assets, so assuming you don't delete the files in the dotnet folder, then you should be fine.
If you just want to exempt the dotnet folder from any delete actions, as if it were a not part of your project at all, but its in a subfolder the web server and you want to not touch it, then I would suggest using the skip option in msdeploy with wildcards. I've only used it for files, but it should work for folders too. It goes like so:
-skip:objectName=filePath,absolutePath=app_offline\.*
There's documentation here: http://technet.microsoft.com/en-us/library/dd569089%28WS.10%29.aspx
Search the page for
-skip:skipAction=

You could also add a skip setting with name of the folder you wish to not by synced, like in the following msdeploy call:
msdeploy
-verb:sync
-source:contentPath="C:\Data\Personal\My Repo\MSDeploy\MultiSkip\Source"
-dest:contentPath="C:\Data\Personal\My Repo\MSDeploy\MultiSkip\Dest"
-skip:objectName=dirPath,absolutePath="DotNet"
[I took the example from the answer to this question.]

Related

How can I get to the root folder of another project in a .NET Core solution?

I need to read the settings file (appsettings.json) from another project in my solution. When I use:
Directory.GetCurrentDirectory()
From within the current project, I get the following path:
{projectRootFolder}\bin\Debug\netcoreapp3.0\
My question is: How can I get to the exact same folder in another project in the same solution? Or is there a better way to access the settings file from another project within the current solution?
If I understand the problem correctly there are two misconceptions:
It has little sense to access output directory of an another project as the structure has sense in compile time only. You will not have the same structure in run-time once the application is "published".
The Directory.GetCurrentDirectory() returns the current working directory. It is just a coincidence to be set to project output directory by Visual Studio. It can be totally different directory.
It is not clear to me what exactly you are trying to achieve. I recommend using the configuration system provided by .net core to access the configuration and add that other appsettings.json as another configuration provider.
If you really need to open the settings file then the project with the settings file (A) should mark the file as "Copy to Output Directory" and the project to open the file (B) should reference the project A. So the settings file will be copied to output of the project A too.
What you're attempting to do is not possible. There's no inherent way for ASP.NET Core to know where a totally different app running in a totally different process is located.
If you need to access appsettings.json from another project, then you would need to include it as a linked file in your project, and set it to copy to output. Then, you're accessing it actually from your project (which is all you can do), but the file itself is shared.
However, this is almost always a bad idea, and usually a sign that you're doing something wrong. If you truly do need to share the settings, then what you should be doing is putting them in a distributed config provider like Azure Key Vault or similar, where both projects can independently access the settings from a common store.

TFS 2015 Artifacts always empty upon build

I have created build definition which runs successfully. Now I want to create a release definition on the successful build, for which it is asking for artifacts.
When I tried browsing "Drop" folder, I found it empty.
Below are the images from Copy Files step and Publish build artifacts step.
I also tried instructions from The item MY_ARTIFACT_NAME in container XXX could not be found
But no luck. Please help.
I believe that you should use $(build.sourcesdirectory) (or a path relative to) as the source folder if you want to copy files which are not checked in.
Also, from the documentation of the Copy Files step
The pattern is used to match only file paths, not folder paths. So you should specify patterns such as **\bin\** instead of of **\bin.
Try changing the contents pattern to **\bin\** and see if that helps.

Common wwwroot folder for multiple websites in MVC 6

I have multiple websites which use /wwwroot/assets folder (html theme, css and javascript files) to load the static content.
Currently I am copying assets folder in each site. All of my projects are sitting under a common parent directory.
I don't want to copy the /wwwroot/assets folder into each website. Is there a way to share one assets folder between all sites. May be by providing a direct file system path or something?
At the moment it's not clear from the documentation what sorts of values the webroot key in the project.json file will accept, but so far it would appear that Visual Studio doesn't care for very complicated paths. For example, setting the value to ../wwwroot causes the entry to disappear in the Solution Explorer.
If you look at the kpm code that bundles your project up for deployment, it appears to combine your project's directory with whatever is stored in the wwwroot key, so even though Visual Studio may not understand it, relative paths appear to be supported. Using kpm bundle from the command line confirms this, and a directory above src bundles correctly when using a relative path.
Depending on your particular needs, there is one way that should work that makes kpm and Visual Studio happy, but it will depend on your build environment as to whether that is a good option for you.
Windows, OSX, and Linux all support creating symbolic links for directories, which would allow you to have your assets directory in one location in the filesystem and then create links to it elsewhere. For example, if you had assets in /projects/shared/assets, you could create a link in both of your other projects (e.g. /projects/project1/src/wwwroot/assets) that point to the "real" location.
In Windows, the command would might something like this
mklink /j "C:\link\to\create" "C:\path\to\assets"
So if you did
mklink /j "C:\source\shared\assets" "C:\source\project1\src\wwwroot\assets"
project1 would appear to have an assets directory inside of wwwroot and the build process would be happy since it would appear to each project that the files were local. One thing to note here is that Windows supports a number of different sorts of links. /j specifically creates a junction rather than a true symbolic link. The differences are a bit subtle, but this is a good description of the differences. It is enough to know that if you're working locally, the /j command doesn't require administrative rights and Visual Studio and kpm will both be happy.
In OSX and Linux, the command is similar:
ln -s /link/to/create /path/to/assets
and like Windows, they support different sorts of links.
In any case, under the right circumstances, this might work well without needing any special support from the new ASP.NET project structure, but it would be nice to eventually have that as well.

how do deploy an msbuild zip package locally or remotely without requiring IIS involvement

I am in the process of creating an application to allow the automation of application deployments, (https://github.com/twistedtwig/AutomdatedDeployments#readme).
The idea being that everything is in source control, application files, application configuration as well as IIS configuration. My application allows the solution to auto deploy, (adding a post build setp to the sln / proj file), after a build to the dev machine. It will allow the CI server to auto deploy to its machine for testing as well as the CI Server pushing successful builds to QA / Test / production servers. One of the issues I have with msdeploy is the requirement of IIS to be setup with the website / application before hand, (which my app is trying to get around).
So far I can create, update and remove, app pools, websites and applications via config files automatically. I can sync files and folders fine. The last step was to use the /target:package switch in msbuild to create clean file structures for web deployments. For example I would run a command like:
msbuild.exe myMvcSite.csproj /target:clean /target:package /p:Configuration=Release /p:_PackageTempDir=C:\websites\mySite /p:PackageLocation=C:\dropLocation\mySite.zip
This creates a nice zip file with the internal file path of "C_C\wbesites\mySite" ready (as I understand it) to be sync'd to the production server.
My issue is how I deploy this zip file. I want it to be independent of any IIS information, i.e. I am simply pushing the files / folders to a location, (either on the local machine for developers, or remote for testing etc). The setup of IIS with app pools and sites etc would be taken care of separately. Some of the commands (and their output) I have tried are below:
"C:\Program Files\IIS\Microsoft Web Deploy v2\msdeploy.exe" -verb:sync -source:package="C:\Temp\deploy\installer\test\testPackage.zip" -dest:auto
Info: Adding sitemanifest (sitemanifest).
Error: The application pool that you are trying to use has the 'managedRuntimeVersion' property set to 'v2.0'. This application requires 'v4.0'.
Error count: 1.
and
"C:\Program Files\IIS\Microsoft Web Deploy v2\msdeploy.exe" -verb:sync -source:package="C:\website\installer\testPackage.zip" -dest:contentpath=C:\temp\mytest
Error: Source (sitemanifest) and destination (contentPath) are not compatible for the given operation.
Error count: 1.
The first command I am trying to let it unpack the files with the structure it has. It seems to be upset about app pool stuff though, (which I don't want it to touch).
The second I am trying to get around the "auto" bit but this isn't happy either.
I am struggling to find much information about this process.
The only way I can see how I might achieve this at the moment is to not use msdeploy for it, but to create my own task to integrate the file structure and do the file syncing my self, (not ideal).
I ended up coding around this issue, rather than being able to solve it.
I take the zip package:
unzip in a temp location
find the final path it will be going to (normally from archive.xml)
check to see if I am merging the folders or doing a clean install, (i.e. do I delete the destination folder first).
copy / push files to end location, (normally with msdeploy).
I open sourced my solution to this: https://github.com/twistedtwig/AutomatedDeployments

FTP only changed files in MSBuild

An MSBuild project copies its output to a directory on a server. Each day, only a few files change and most have an older creation date.
I can FTP this to a remote server with MSBuild tasks. But how can I do this FTP and only copy the few files that have changed?
To do this you'll need something that will manage the sync for you - that is that will keep track of what file is where and update accordingly.
We have used FTPSync to do the file sync bit very tidly for a number of sites.
From MSBuild you can call an external program - so putting the two together will probably work providing your are consistently synching from the same location (otherwise its going to be more interesting!)