I ran into a bit of a problem today when trying to copy files from one folder to another. I wanted to copy all files in a folder structure except the .cs files (ie I wanted to exclude them). This can be done with XCOPY but I didn´t get it working (since I wanted to do this from inside a post build event in Visual Studio). I finally decided to use ROBOCOPY instead but I ran into some issues using that in a post build event. I didn´t find a lot of information on the Internet about it so I have decided to write an article about it to maybe help others.
I´ll start with explaining why I wan´t to copy files like this.
Have a look at the following folders in VS and IIS (the image below). As you can see I use the same folder names in VS for CONTROLTEMPLATES and LAYOUTS as the virtual paths in IIS (which in turn points to those folders inside the 12 hive) and I´ll explain why very soon. I´ll place all my ascx files in _controltemplates and the master, aspx, css, js, image files etc in the _layouts folder in my VS solution.
* As a sidenote, in 2010 this sort of thing is called a mapped folder strcuture. I got the idea from 2010 actually.
What this means is that if I wan´t to reference a masterpage or a usercontrol in an applicationpage I will get full support from Visual Studio.
This is due to the fact that if I reference a masterpage like ~/_layouts/Custom/Masterpages/MyMaster.master VS will regognize the virtual path (because I use _layouts as the name of the folder) and give me full intellisense for content placeholder, css files, etc.
The same applies to ascx files that live in ~/_controltemplates/Custom/MyControl.ascx and this means that if I reference that in my aspx application page it will recognize it as a MyControl class and not as a standard UserControl class. Normally you have to convert your usercontrol to a mycontrol in order to use public properties and methods on it. (MyUserControl as MyControl)
If you come from the asp.net world into SharePoint you will have major issues with this sort of problems. This is a fancy way around it I think. In 2010 it will be gone…puh.
Now to the real problem.
Since this is SharePoint 2007, and we use wsp builder (at least now) we have to copy the files inside _controltemplates and _layouts at the root level into their corrosponding folder in the 12 hive. This is normally done using a postbuild event in visual studio that takes care of the copying before we run wsp builder.
Here is where I had some problems with XCOPY since I don´t want to copy the .cs files into the 12 hive. I found a couple of solutions on the Internet using a textfile with exclusion but it didn´t seem to work withhin a postbuild event though.
The solution to this problem was finally to download ROBOCOPY and to use that instead since it is a bit more flexible.
First things first, download Windows Server 2003 Resource Kit Tools (includes ROBOCOPY) from here and install it. Don´t forget to restart Visual Studio afterwards to have it pick up the new environmental variables otherwise you might get an annoying error 9009 message (which means that it can´t find the .exe) when running the post build task.
* If using Win7, Vista or Win2008 (in this case Win2003) you don´t have to install ROBOCOPY it is included in the OS.
This is how the actual post build looks like:
ROBOCOPY "$(ProjectDir)\"_controltemplates\ "$(ProjectDir)\"12\TEMPLATE\CONTROLTEMPLATES\ /S /COPY:DT /XF *.cs ROBOCOPY "$(ProjectDir)\"_layouts\ "$(ProjectDir)\"12\TEMPLATE\LAYOUTS\ /S /COPY:DT /XF *.cs if errorlevel 4 goto BuildEventsFailed if errorlevel 0 goto end :BuildEventsFailed echo FILECOPY for $(ProjectName) FAILED exit 1 :end echo FILECOPY for $(ProjectName) COMPLETED OK exit 0
Some things worth noting are that I have to escape any possible spaces in the paths (UNC) that are sent to ROBOCOPY that is why I use ” ” (double quotation marks ).
The little if statement block I found on the web. It seems like ROBOCOPY sends the wrong code to studio which then causes it to display an error. That little if statement block fixes that issue.
I also use an external bat file to do the same thing but this one I use just for dev purposes to copy things to the local 12 hive. The script looks like this:
@echo off Set SourceDir="%1%" Set TEMPLATEDIR="%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE" ROBOCOPY %SourceDir%_controltemplates\ %TEMPLATEDIR%\CONTROLTEMPLATES\ /S /COPY:DT /XF *.cs ROBOCOPY %SourceDir%_layouts\ %TEMPLATEDIR%\LAYOUTS\ /S /COPY:DT /XF *.cs
Finally I use an external tool to call that bat file and this is because, let´s face it, when we develop a solution for SharePoint we don´t want to build/retract/remove/add/deploy a wsp everytime we make a change. Sometimes it is fine to just copy files to the 12 hive.
* This has unfortunately not been taken seriously by MS in 2010 either but there we have better support for mapped folders and extending studio in the way we wan´t.
The $(ProjectDir) will translate to the directory path where the project is built at. This in turn will be sent as a parameter to the bat file and used as part of the source path together with ROBOCOPY.
So now I have mapped a keyboard shortcut to this external tool and wham all the files except the .cs files are copied to the 12 hive. Just hoping SPVisualDev will support this in the next release, ie a mapped folder solution.