Generar un bacpac en Azure desde código

Hace unos días, buscando en Internet, encontré que Microsoft dispone de un servicio de generación de ficheros bacpac en Azure público pero no documentado. A este servicio, se le indica la base de datos de Azure, de la cual se quiere generar el fichero bacpac y la cuenta de almacenamiento de Azure donde se quiere guardar, y el servicio genera el fichero bacpac.

El fichero de bacpac sirve de backup de base de datos, puesto que a partir de él, podemos restaurar la base de datos original en Azure. También nos sirve para migrar datos de Azure a On-Premise utilizando el wizard de la herramienta SQL Management Studio 2012, el cual nos permite restaurar la base de datos a partir del fichero bacpac.

Ahora vamos a ver como utilizar este servicio desde código C#. Lo primero es añadir en nuestro proyecto una referencia al servicio (https://am1prod-dacsvc.azure.com/DACWebService.svc/mex). Esto nos crea las clases ConnectionInfo, BlobStorageAccessKeyCredentials y ExportInput que utilizaremos en la llamada al servicio.

A continuación, adjunto una clase que he preparado y que lo único que hace es facilitar el uso del servicio web.

Clase AzureDatabaseBackup

public class AzureDatabaseBackup
{
    public static class DacWebServiceUrls
    {
        public static readonly string NorthEurope = "https://db3prod-dacsvc.azure.com/DACWebService.svc";
        public static readonly string WestEurope = "https://am1prod-dacsvc.azure.com/DACWebService.svc";
        public static readonly string NorthCentralUS = "https://ch1prod-dacsvc.azure.com/DACWebService.svc";
        public static readonly string SouthCentralUS = "https://sn1prod-dacsvc.azure.com/DACWebService.svc";
        public static readonly string EastAsia = "https://hkgprod-dacsvc.azure.com/DACWebService.svc";
        public static readonly string SoutheastAsia = "https://sg1prod-dacsvc.azure.com/DACWebService.svc";
    }

    private string dacWebServiceUrl = DacWebServiceUrls.WestEurope; //Default
    private ConnectionInfo connectionInfo = new ConnectionInfo();
    private BlobStorageAccessKeyCredentials credentials = new BlobStorageAccessKeyCredentials();

    public AzureDatabaseBackup() {}

    public AzureDatabaseBackup(string dacWebServiceUrl)
    {
        this.dacWebServiceUrl = dacWebServiceUrl;
    }

    public void SetDatabaseConnectionInfo(string server, string database, string user, string password)
    {
        this.connectionInfo.ServerName = server;
        this.connectionInfo.DatabaseName = database;
        this.connectionInfo.UserName = user;
        this.connectionInfo.Password = password;
    }

    public void SetAzureStoreInfo(string backupFileUrl, string storageAccountKey)
    {
        this.credentials.Uri = backupFileUrl;
        this.credentials.StorageAccessKey = storageAccountKey;
    }

    public void RequestBacpac()
    {
        ExportInput exportInport = new ExportInput();
        exportInport.BlobCredentials = this.credentials;
        exportInport.ConnectionInfo = this.connectionInfo;

        WebRequest request = WebRequest.Create(this.dacWebServiceUrl + "/Export");
        request.Method = "POST";
        request.ContentType = "application/xml";
        using (Stream requestStream = request.GetRequestStream())
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(ExportInput));
            serializer.WriteObject(requestStream, exportInport);
        }

        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new ApplicationException(string.Format(
                    "Error en el backup de '{0}'. Error = '{1}', '{2}'"
                    , this.connectionInfo.DatabaseName
                    , (int)response.StatusCode, response.StatusDescription));
            }
        }
    }
}

Solicitud de creación de un fichero bacpac
Y por último, un ejemplo de como utilizar la clase que acabamos de añadir. Notar que hemos de indicar el centro de datos donde reside nuestra base de datos para que el rendimiento sea óptimo.

AzureDatabaseBackup adb = new AzureDatabaseBackup(AzureDatabaseBackup.DacWebServiceUrls.WestEurope);
adb.SetAzureStoreInfo("https://myaccount.blob.core.windows.net/mycontainer/myfile.bacpac"
                    , "mystoreaccountkey");
adb.SetDatabaseConnectionInfo("myserver.database.windows.net", "mydatabase", "myuser", "mypassword");

adb.RequestBacpac();