Visual Studio 2010 Database Deployment API - Part 2

Since posting the first code sample on how to leverage the Visual Studio Database Deployment API, I have had a number of folks contact me and ask how to do the same, but also comprehend the database references, options set in the project, refactor log, pre and post deployment scripts, etc. The short answer is that you include the deployment manifest in your use of the API. Including the manifest will use all the settings from your project and also load up referenced database models and artifacts.

Below I have updated the sample to use the manifest file to drive the options for the deployments. It assumes you are using integrated security so it can also pull the connection string from the manifest file. The sample basically drives the database project deployment engine from a console app. 

 using System;
using System.Diagnostics;
using System.IO;
using Microsoft.Data.Schema;
using Microsoft.Data.Schema.Sql;
using Microsoft.Data.Schema.Extensibility;
using Microsoft.Data.Schema.Build;
using Microsoft.Build.Evaluation;
 
namespace DeployLocalModel
{
    class Program
    {
        static void Main(string[] args)
        {
            string manifestFilePath = null;
            ISchemaDeploymentController sdController = null;
            Project projectManifest = null;
            FileInfo manifestFile = null;
            SchemaDeployment sdEngine = null;
            SchemaDeploymentConstructor sdConstructor = null;
            bool hasDeploymentChanges = false;
            bool pastPredeploymentPayload = false;
 
        try
        {
            manifestFilePath = @".\LocalModel.deploymanifest";
 
            if (args.Length > 0)
            {
                manifestFilePath = args[0];
            }
 
            manifestFile = new FileInfo(manifestFilePath);
            if (!manifestFile.Exists)
                throw new Exception("Manfiest file does not exist!");
            
            //Load manifest into MSBUILD Project so we can pull values from it
            projectManifest = new Project(manifestFile.ToString());
 
            /*Create a extension manager so we can load the SQL100 DSP 
              and utilize its implementation of the deployment engine*/
            ExtensionManager extensionManager = 
                new ExtensionManager(typeof(Sql100DatabaseSchemaProvider).FullName);
            
            // Create the deployment controller
            sdConstructor = 
                extensionManager.DatabaseSchemaProvider.GetServiceConstructor<SchemaDeploymentConstructor>();
 
            //Create a new error manager so we can capture the error messages
            ErrorManager errorManager = new ErrorManager();
 
            /*Attach error manager to the deployment constructor. 
            This will allow us to get errors from the deployment contributor later on */
            sdConstructor.Errors = errorManager;
 
            //Set up the deployment engine constructor of what we plan to deploy
            sdConstructor.Setup(
                new FileInfo(projectManifest.GetPropertyValue("SourceModel")), 
                projectManifest.GetPropertyValue("TargetConnectionString"));
 
            //Create an instance of the deployment engine
            sdEngine = sdConstructor.ConstructService();
 
            //Load manifest so other artifacts and options are considerred
            sdEngine.Configure(projectManifest, manifestFile.Directory);
 
            //Do not deploy to dataabase, yet
            sdEngine.SetDeployToDatabase(false);
            //Execute the engine to create our deployment plan
            sdEngine.Execute();
 
             // Get access to the plan so we call walk through it and later execute it
            DeploymentPlan deploymentPlan = sdEngine.Plan;
 
            #region WalkTheDeploymentPlan
            //Start with the first step in the plan and start iterating through it
            DeploymentStep deploymentStep = deploymentPlan.Head;
            while (deploymentStep != null)
            {
#if DEBUG
                //Send deployment step contents to output window
                Debug.Print("Deploy Step {0} contains:\n\r {1}",
                                deploymentStep.GetType().FullName,
                                deploymentStep.Action());
#endif
                /*Check and see if we are past the predeployment script so were can 
                  determine if there are any incremental deployment changes*/
                if (deploymentStep is EndPreDeploymentScriptStep)
                    pastPredeploymentPayload = true;
 
                if (deploymentStep.Action() != "")
                {
                    /*Test to see if we are deploying any changes, 
                      if not we will short circuit later on.*/
                    if (deploymentStep is DeploymentScriptDomStep && pastPredeploymentPayload)
                    {
                        hasDeploymentChanges = true;
                        break;
                    }
 
                }
                deploymentStep = deploymentStep.Next;
            }
 
            #endregion WalkTheDeploymentPlan
 
            if (hasDeploymentChanges)
            {
                //Create a controller se we can work with the deployment plan
                sdController = sdEngine.CreateController();
 
 
                // Setup our event handler so we can listen to events from deployment engine
                sdController.DeploymentMessage
                    += delegate(object sender, DeploymentContributorEventArgs deployArg)
                    {
                        Console.WriteLine("{0}", deployArg.Message.Message);
                    };
 
                //Deploy the model to the target database using the plan
                sdController.UpdateDatabase(deploymentPlan);
            }
            else
            {
                Console.WriteLine("No deployment changes to make!");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        finally
        {
            if (sdController != null)
            {
                sdController.Dispose();
            }
            Console.WriteLine("Execution complete. Strike any key to exit.");
            Console.ReadKey();
        }
    
        }
    }
}

If you want to start out with the sample already coded up you can download it from my SkyDrive.