I’ve lately been working on getting a build setup using Visual Studio Team Services. The build works fine, but deploying everything is a different story. I’m going to rewind back to the basics of how to setup a minimal build in your visual studio solution. If you aren’t familiar with postbuild files then head over to JR’s blog.

I’ve adapted this method over the years of working with different clients, by both seeing what they do and what fits my every day needs.

The projects all start out in the same sort of folder layout. Let’s use the Best Friends Animal Society as an example. Each line is a folder.


The Visual Studio projects all live in BFAS\Customizations and the dlls that the project uses live in BFAS\DLLReferences. This works extremely well because now all of your projects can use the ..\..\DLLReferences for the hit folder for the references. Now the references for the projects aren’t dependent on a developers installed versions.

With Blackbaud development we really only have 3 different types of projects that are used a lot: Catalog or class project, UIModel, and BBIS. I now create a Build project that’s just a class library.

I navigate to the project properties and set the configuration to: All Configurations. From there I set the following as the build output path for:

Catalog or class project: ..\BuildOutput\bbappfx\vroot\bin\custom\
UIModel project: ..\BuildOutput\bbappfx\vroot\
BBIS project: ..\BuildOutput\NetCommunity\
Build project: ..\BuildOutput\Build\

In my solution properties I set all of the other projects as a dependency for the build project so that I know it will always run last.


Now in my UIModel projects for the html files I create a browser folder and put the htmlforms folder in there.


I make sure that every html and js file has the “Copy to Output Directory” property set to “Copy always”.

For the BBIS projects I set the structure up like so:

I then set any file’s “Copy to Output Directory” property in the scripts/custom and styles/custom to “Copy always”. I do the same thing for the .ascx files in the custom/display parts and custom/edit parts folders. However I make sure to set the .ascx.designer.vb and .ascx.vb files to “Do not copy”.

Now once you rebuild the solution everything should be outputted to your ..\BuildOutput\ folder. In the older days before I used a Build project I would have a postbuild in every project that moved all of the files around for me. But now I just put a postbuild in the Build project.

I make sure to set the post build event in the Build project to this: “$(ProjectDir)”postbuild.bat

Then in my postbuild.bat file, long story short it just moves all of the files into a proper Blackbaud CRM and Internet Solutions directory, I have the following:
set source_folder_bbis=%~dp0..\BuildOutput\NetCommunity
set source_folder_build=%~dp0..\BuildOutput\Build
set source_folder_crm=%~dp0..\BuildOutput\bbappfx\vroot

echo move bbis dll files
xcopy "%source_folder_bbis%\*.dll" "%source_folder_bbis%\bin\" /y /d /r

echo delete unneeded files from build project
del "%source_folder_build%\*.*" /f /q

echo delete unneeded xml files
del "%source_folder_bbis%\*.xml" /f /q

echo delete unneeded pdb files
del "%source_folder_bbis%\*.pdb" /f /q

echo delete unneeded config files
del "%source_folder_bbis%\*.config" /f /q

echo delete unneeded code analysis files
del "%source_folder_bbis%\*.lastcodeanalysissucceeded" /f /q

echo delete unneeded dll files
del "%source_folder_bbis%\*.dll" /f /q

echo move uimodel dll files
xcopy "%source_folder_crm%\*.dll" "%source_folder_crm%\bin\custom\" /y /d /r

echo delete unneeded dll files
del "%source_folder_crm%\*.dll" /f /q

echo delete unneeded xml files
del "%source_folder_crm%\*.xml" /f /q

echo delete unneeded pdb files
del "%source_folder_crm%\*.pdb" /f /q

echo delete unneeded config files
del "%source_folder_crm%\*.config" /f /q

echo delete unneeded code analysis files
del "%source_folder_crm%\*.lastcodeanalysissucceeded" /f /q

echo delete unneeded xml files
del "%source_folder_crm%\bin\custom\*.xml" /f /q

echo delete unneeded pdb files
del "%source_folder_crm%\bin\custom\*.pdb" /f /q

echo delete unneeded config files
del "%source_folder_crm%\bin\custom\*.config" /f /q

echo delete unneeded code analysis files
del "%source_folder_crm%\bin\custom\*.lastcodeanalysissucceeded" /f /q

if not exist "%~dp0postbuild.user.bat" goto end

echo running postbuild.user.bat

echo postbuild.user.bat not found, skipped.

The last bit at the end is what is used to deploy the files to each developer’s specified environment.

Now in my postbuild.user.bat I have what moves the files into my specified local environment. Each user can put an entry in here.

set source_folder_crm=%~dp0..\BuildOutput\bbappfx\vroot
set source_folder_html=%~dp0..\BuildOutput\bbappfx\vroot\browser\htmlforms\custom
set source_folder_bbis=%~dp0..\BuildOutput\netcommunity

if %computername%==CHRISWPC goto :CWHISENHUNT
if %computername%==DEV2PC goto :DEV2

echo set target folder
set target_folder_crm=C:\Program Files\Blackbaud\4\bbappfx\vroot
set target_folder_bbis=C:\Program Files\Blackbaud\4\netcommunity

goto :ALWAYS

echo set target folder
set target_folder_crm=E:\Program Files\Blackbaud\bbappfx\vroot
set target_folder_bbis=E:\Program Files\Blackbaud\netcommunity

goto :ALWAYS


echo copy crm dlls
xcopy "%source_folder_crm%\bin\custom\*.dll" "%target_folder_crm%\bin\custom\" /y /d /r

echo copy crm html files
xcopy "%source_folder_html%\*.html" "%target_folder_crm%\browser\htmlforms\custom\" /y /d /r /s

echo copy bbis dlls
xcopy "%source_folder_bbis%\bin\*.dll" "%target_folder_bbis%\bin\" /y /d /r

echo copy bbis root aspx files
xcopy "%source_folder_bbis%\*.aspx" "%target_folder_bbis%\" /y /d /r

echo copy bbis display parts
xcopy "%source_folder_bbis%\custom\display parts\*.ascx" "%target_folder_bbis%\custom\display parts\" /y /d /r

echo copy bbis edit parts
xcopy "%source_folder_bbis%\custom\edit parts\*.ascx" "%target_folder_bbis%\custom\edit parts\" /y /d /r

goto :END

As you can see from the screenshot of my Build project above there is a scripts folder. I find it useful to keep all of my scripts that are related to my customizations in there.

Right now this is what I use and it works great. I’m in the process of setting up an automated CI build using Visual Studio Team Services, which I will get into in more depth once I have it working. The plan is to have it do this:

Restore a BB database
Run pre-build scripts
Build BB solution
Deploy files
Load packages
Run post-build scripts

This would happen every time there is a check-in in the dev branch and once nightly with a deployment to test.

Our main branch would deploy nightly to our staging environment and then production would deploy to production once a week.

I would also like to get the “Restore a BB database” to use the latest nightly backup from production. I have jobs setup to move the databases now, I just need to put it all together.

This is part 1 of 238423 parts in getting this to all work well together.

Happy coding!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s