X Blogs

who you gonna call?

Automatic SQL Azure backup part 1

clock November 18, 2011 23:24 by author Rok Bermež
Backup for SQL Azure was one of the most voted-on features since the beginning. Sure, we had SQL Migration wizard, BCP, SSIS, PowerShell cmdlets from Cerebrata , and later a very nice tool from RedGate (that I still use a lot) - SQL Azure backup. All of them have one flaw, there are either impossible or very hard to use for automatic backups that require no on premises infrastructure.
For a while now, Import and Export CTP functionality has been available through Windows Azure management portal, that exports or imports Sql DacPac package. This is the exact functionality that should be integrated with my SQL Azure using cloud applications.
MSDN documentation for that REST API seems to be completely lacking, but fortunately there are some SQL DAC Examples on CodePlex project that can we can use to see how it’s done.
First, we add a service reference to http://dacdc.cloudapp.net/DACWebService.svc/mex and generate required proxy classes.

Now we can make WebRequests for specific actions (import,export, status) to URLs, that are specific to each Windows Azure datacenter. Here is the mapping:

RegionUrl
North Central US https://ch1prod-dacsvc.azure.com/DACWebService.svc
South Central US https://sn1prod-dacsvc.azure.com/DACWebService.svc
North Europe https://db3prod-dacsvc.azure.com/DACWebService.svc
West Europe https://am1prod-dacsvc.azure.com/DACWebService.svc
East Asia https://hkgprod-dacsvc.azure.com/DACWebService.svc
Southeast Asia https://sg1prod-dacsvc.azure.com/DACWebService.svc

 

Export

To create a backup to storage we need to create an object of type ExportInput and POST it to datacenters url + “/export”.

 

public Guid ExportToStorage(string storageContainer, string fileName, BlobContainerPublicAccessType blobContainerPublicAccessType = BlobContainerPublicAccessType.Off)
        {
            var blobCredentials = GetBlobCredentials(storageContainer, fileName, true, blobContainerPublicAccessType);
            var exportRequest = new ExportInput
            {
                BlobCredentials = blobCredentials,
                ConnectionInfo = _connectionInfo
            };
            var req = GetRequest(new Uri(_dataCenterUrl + "/Export"), RequestMethod.POST);
            var serializer = new DataContractSerializer(typeof(ExportInput));
            var requestStream = req.GetRequestStream();
            serializer.WriteObject(requestStream, exportRequest);
            requestStream.Close();
            var resp = req.GetResponse();
            return GetGuidFromResponse(resp);
        }
        private BlobStorageAccessKeyCredentials GetBlobCredentials(string storageContainer, string fileName, bool createIfNotExist = false, BlobContainerPublicAccessType blobContainerPublicAccessType = BlobContainerPublicAccessType.Off)
        {
            var storageCredentials = new StorageCredentialsAccountAndKey(_storageConnectionInfo.AccountName, _storageConnectionInfo.AccountKey);
            var storageAccount = new CloudStorageAccount(storageCredentials, _storageConnectionInfo.UseHttps);
            var cloudBlobClient = storageAccount.CreateCloudBlobClient();
            var cloudBlobContainer = cloudBlobClient.GetContainerReference(storageContainer);
            if (createIfNotExist)
            {
                if (cloudBlobContainer.CreateIfNotExist())
                {
                    var permissions = cloudBlobContainer.GetPermissions();
                    permissions.PublicAccess = blobContainerPublicAccessType;
                    cloudBlobContainer.SetPermissions(permissions);
                }
            }
            var cloudBlob = cloudBlobContainer.GetBlobReference(fileName);
            var backupBlobUri = cloudBlob.Uri.ToString();
            var blobCredentials = new BlobStorageAccessKeyCredentials
            {
                StorageAccessKey = _storageConnectionInfo.AccountKey,
                Uri = backupBlobUri,
            };
            return blobCredentials;
        }
        private HttpWebRequest GetRequest(Uri uri, RequestMethod requestMethod)
        {
            var req = (HttpWebRequest)WebRequest.Create(uri);
            req.Method = requestMethod.ToString().ToUpper();
            req.ContentType = "application/xml";
            return req;
        }

Import

For import the process is very similar, we have object of type ImportInput and POST it to datacenters url + “/import”.

 

 public Guid ImportFromStorage(string storageContainer, string fileName, SqlAzureEdition sqlAzureEdition = SqlAzureEdition.Web, SqlAzureSize sqlAzureSize=SqlAzureSize.GB_1, string newDbName=null)
        {
            var blobCredentials = GetBlobCredentials(storageContainer,fileName);
            ImportInput importRequest = new ImportInput();
            BlobCredentials creds = blobCredentials;
            importRequest.BlobCredentials = creds;
            importRequest.AzureEdition = sqlAzureEdition.ToString().ToLower();
            importRequest.DatabaseSizeInGB = (int)sqlAzureSize;
            importRequest.ConnectionInfo = (String.IsNullOrEmpty(newDbName)) ? _connectionInfo : new ConnectionInfo() { DatabaseName = newDbName, ServerName = _connectionInfo.ServerName, UserName = _connectionInfo.UserName, Password = _connectionInfo.Password};
            var req = GetRequest(new Uri(_dataCenterUrl + "/Import"), RequestMethod.POST);
            var serializer = new DataContractSerializer(typeof(ImportInput));
            var requestStream = req.GetRequestStream();
            serializer.WriteObject(requestStream, importRequest);
            requestStream.Close();
            var resp = req.GetResponse();
            return GetGuidFromResponse(resp);
        }

Status

Both actions return GUID representing current action that we can use to check if operation was successful. We do this by making GET request to datacenters url + “/status? servername={0}&username={1}&password={2} &reqId={3}”. If we want to get history and their statuses for this datacenter we can make the same request without reqId.

 

        public StatusInfo GetStatusInfo(Guid requestId)
        {
            string uriBuilder = _dataCenterUrl + string.Format("/Status?servername={0}&username={1}&password={2}&reqId={3}", _connectionInfo.ServerName, _connectionInfo.UserName, _connectionInfo.Password, requestId.ToString());
            var req = GetRequest(new Uri(uriBuilder), RequestMethod.GET);
            var response = req.GetResponse();
            var statusInfos = GetStatusInfoFromResponse(response);
            return statusInfos[0];
        }

 

Here ( SqlAzure.rar (22,71 kb) ) you can download a complete library that you can use in your Azure Worker tasks to automatically back up you SQL Azure databases. Next.... how to create cheduler that uses it.

 



Azure AppFabric Cache HowTo

clock May 3, 2011 04:24 by author Rok Bermež
Well since we now have Azure AppFabric Cache available, let’s get a head start on how to use it in your Cloud ASP.NET (MVC) application. First, you need to have AppFabric 1.0 April Refresh SDK installed on your machine so grab it at here.
Next, go to Windows Azure Management portal. Log in, go to AppFabric/Cache and create new service namespace: wait for the service to be activated.

Then click 'View Client Configuration Button'

you will get a nice pre prepared configuration settings (with all those pesky security information included) for your app:
now we have all the pieces of the puzzle ready, all we have to do is to add references to caching dlls (located at C:\Program Files\Windows Azure AppFabric SDK\V1.0\Assemblies\NET4.0\Cache) to our application and change web.config with the settings given by previous step.

You would always need to put cache section in <configSections> node:
<section name="dataCacheClients" 
             type="Microsoft.ApplicationServer.Caching.DataCacheClientsSection,
Microsoft.ApplicationServer.Caching.Core"
allowLocation="true" allowDefinition="Everywhere"/>
and configure your Cache EndPoints:
<dataCacheClients>
    <dataCacheClient name="default">
      <hosts>
        <host name="ntkonferenca.cache.windows.net" cachePort="22233" />
      </hosts>
      <securityProperties mode="Message">
        <messageSecurity
authorizationInfo="1AmN0tT371NgUtH@T">
        </messageSecurity>
      </securityProperties>
    </dataCacheClient>
    <dataCacheClient name="SslEndpoint">
      <hosts>
        <host name="ntkonferenca.cache.windows.net" cachePort="22243" />
      </hosts>
      <securityProperties mode="Message" sslEnabled="true">
        <messageSecurity
authorizationInfo="1AmN0tT371NgUtH@T">
        </messageSecurity>
      </securityProperties>
    </dataCacheClient>
  </dataCacheClients>
If your application uses Session State and you want it to use Azure AppFabric Cache (which you do) you change your <sessionState> node to:
    <sessionState mode="Custom" customProvider="AppFabricCacheSessionStoreProvider">
      <providers>
        <add name="AppFabricCacheSessionStoreProvider"
             type="Microsoft.Web.DistributedCache.DistributedCacheSessionStateStoreProvider, 
Microsoft.Web.DistributedCache"
cacheName="default" useBlobMode="true" dataCacheClientName="default" /> </providers> </sessionState>
and the same for OutputCache by changing <caching> note:
<caching>
    <outputCacheSettings enableFragmentCache="true" defaultProvider="DistributedCache">
      <outputCacheProfiles>
        <add name="default" duration="43000" />
        <add name="DistributedCache"
                       type="Microsoft.Web.DistributedCache.DistributedCacheOutputCacheProvider, 
Microsoft.Web.DistributedCache"
cacheName="default" dataCacheClientName="default" /> </outputCacheProfiles> </outputCacheSettings> </caching>
That’s it, nothing needs to be changed in your code, your app is configured and ready to be published to the cloud. AppFabric Cache is not a free service even if you won’t be charged anything for its use prior to August 1, 2011. After that the prices are:
  • 128 MB cache for $45.00/month
  • 256 MB cache for $55.00/month
  • 512 MB cache for $75.00/month
  • 1 GB cache for $110.00/month
  • 2 GB cache for $180.00/month
  • 4 GB cache for $325.00/month
In my next post, Ill tackle with using AppFabric Cache without using prepared providers by simple GET and PUT statements (lets get rid of HttpRuntime.Cache as well).

 



Windows Azure AppFabric Caching Service Released

clock April 30, 2011 19:52 by author Rok Bermež

Finally the Azure thingy I’ve been waiting for the most. From the official source:

Today we are excited to announce that the Caching service has been released as a production service.  

The Caching service is a distributed, in-memory, application cache service that accelerates the performance of Windows Azure and SQL Azure applications by allowing you to keep data in-memory and saving you the need to retrieve that data from storage or database.

We provide 6 different cache size options for you to choose from, varying from 128MB to 4GB.  In order for customers to be able to start using the service and evaluate your needs we are running a promotion period in which we will not be charging for the service for billing periods prior to August 1, 2011.

To learn more about the Caching service please use the following resources:

·        Windows Azure AppFabric Caching availability announced!! blog post, including more information on pricing.

·        Video: Introduction to the Windows Azure AppFabric Cache

·        Video: Windows Azure AppFabric Caching – How to Set-up and Deploy a Simple Cache

·        Windows Azure AppFabric FAQ on MSDN

·        MSDN Documentation

The service is already available in our production environment at: http://appfabric.azure.com.

For questions on the Caching service please visit the Windows Azure Storage Forum.

Customers can take advantage of our free trial offer to get started with the Caching service and Windows Azure AppFabric. Just click on the image below and get started today!

 



Manualy Submiting Unobtrusive MVC 3 Ajax Form

clock April 21, 2011 23:21 by author Rok Bermež
If you want to submit Ajax.BeginForm created ajax form a simple this.form.submit() wont work. Well to be exact it will, but not as it was intended. In order to make it work like expected, we can do it like this:
 
Html.DropDownList("selPredavanja",ViewBag.Lectures as SelectList,new { onchange = "Sys.Mvc.AsyncForm.handleSubmit( this.form, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.replace, updateTargetId: 'lectureData' });"})


Windows Azure Cache Dependency

clock April 11, 2011 08:07 by author Rok Bermež

We are supposed to get Windows AppFabric Cache real soon, but till than form time to time we need to synchronize content cached inside our Web roles. SqlDependency is one way, but it cannot solve all problems (especialy those that are not based on SQL data). So to help with the matter I wrote AzureStorageCacheDependency that uses Azure storage to know when data is outdated and cache shloul be cleared. If anyone is in need of something similar, here it goes:

public class AzureStorageCacheDependency : System.Web.Caching.CacheDependency
    {
        private System.Threading.Timer _timer;
        private int _poolTime;
        private CloudBlob _blob;
        private string _key;

        public AzureStorageCacheDependency(string connectionString, string conteinerAddress, string blobAddress, int poolTime = 5000)
        {
            _poolTime = poolTime;
            using (AzureContext azureContext = new AzureContext(true))
            {
                var storageAccount = CloudStorageAccount.Parse(connectionString);
                CloudBlobClient blobStorage = storageAccount.CreateCloudBlobClient();
                CloudBlobContainer container = blobStorage.GetContainerReference(conteinerAddress.ToLower());
                container.CreateIfNotExist();
                _blob = container.GetBlockBlobReference(blobAddress.ToLower());
                if (!Exists(_blob))
                {
                    Reset();
                }
                else
                {
                    _key = _blob.DownloadText();
                }
            }
            _timer = new Timer(new System.Threading.TimerCallback(CheckDependencyCallback), this, 0, _poolTime);
        }



        public void Reset()
        {
            _key = Guid.NewGuid().ToString();
            _blob.UploadText(_key);
        }

        private void CheckDependencyCallback(object sender)
        {
                if (!Exists(_blob) || _key != _blob.DownloadText())
                {
                    NotifyDependencyChanged(this, EventArgs.Empty);
                    _timer.Dispose();
                }
        }

        public static bool Exists(CloudBlob blob)
        {
            try
            {
                blob.FetchAttributes();
                return true;
            }
            catch (StorageClientException e)
            {
                if (e.ErrorCode == StorageErrorCode.ResourceNotFound)
                {
                    return false;
                }
                else
                {
                    throw;
                }
            }
        }
    }

    public class AzureContext : IDisposable
    {
        HttpContext _oldHttpContext;
        bool _restoreOldHttpContext = false;


        public AzureContext(bool forceSettingContextToNull = false)
        {
            if (forceSettingContextToNull)
            {
                _oldHttpContext = HttpContext.Current;
                HttpContext.Current = null;
                _restoreOldHttpContext = true;
            }
            else
            {
                try
                {
                    HttpResponse response = HttpContext.Current.Response;
                }
                catch (HttpException)
                {
                    _oldHttpContext = HttpContext.Current;
                    HttpContext.Current = null;
                    _restoreOldHttpContext = true;
                }
            }
        }


        public void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_restoreOldHttpContext)
                {
                    HttpContext.Current = _oldHttpContext;
                }
            }
        }


        public void Dispose()
        {
            Dispose(true);
        }


        ~AzureContext()
        {
            Dispose(false);
        }
    }


ASP.NET MVC 3 AJAX REDIRECT RESULT

clock April 5, 2011 23:31 by author Rok Bermež
From time to time, we need to selectively redirect the browser to another location as a 
result of an AJAX action. Just returning RedirectResult won’t do the trick (even if we
are used to similar functionality in ASP.NET AJAX in combination with WebForms ). Here
is a very simple RedirectResult thet will be appropriate in those scenarios:

public class AjaxRedirectResult : RedirectResult { public AjaxRedirectResult(string url): base(url){} public override void ExecuteResult(ControllerContext context) { if (context.RequestContext.HttpContext.Request.IsAjaxRequest()) { JavaScriptResult result = new JavaScriptResult() { Script = String.Format("window.location='{0}';",
UrlHelper.GenerateContentUrl(Url, context.HttpContext)) }; result.ExecuteResult(context); } else base.ExecuteResult(context); } }


Windows Azure Platform SDK 1.4 Released

clock March 11, 2011 18:14 by author Rok Bermež

SDK 1.4 is available and it  fixes several significant bugs including the nasty RDP bug and adds capabilities like multiple administrator support from the enhanced Windows Azure Connect portal.

Bug Fixes:

  • Resolved an issue that caused full IIS fail when the web.config file was set to read-only.
  • Resolved an issue that caused full IIS packages to double in size when packaged.
  • Resolved an issue that caused a full IIS web role to recycle when the diagnostics store was full.
  • Resolved an IIS log file permission Issue which caused diagnostics to be unable to transfer IIS logs to Windows Azure storage.
  • Resolved an issue preventing csupload to run on x86 platforms.
  • User errors in the web.config are now more easily diagnosable.
  • Enhancements to improve the stability and robustness of Remote Desktop to Windows Azure Roles.

New Features

  • Windows Azure Connect:
    • Multiple administrator support on the Admin UI.
    • An updated Client UI with improved status notifications and diagnostic capabilities.
    • The ability to install the Windows Azure Connect client on non-English versions of Windows.
  • Windows Azure CDN:
    • Windows Azure CDN for Hosted Services: Developers can now use the Windows Azure Web and VM roles as"origin" for objects to be delivered at scale via the Windows Azure CDN. Static content in a website can be automatically edge-cached at locations through out the United States, Europe, Asia, Australia and South America to provide maximum bandwidth and lower latency delivery of website content to users.
    • Serve secure content from the Windows Azure CDN: A new checkbox option in the Windows Azure management portal enables delivery of secure content via HTTPS through any existing Windows Azure CDN account.

You may download the new Windows Azure 1.4 SDK here.



Windows Azure SDK 1.3 Refresh

clock February 3, 2011 04:09 by author Rok Bermež

Due to numerous bugs, the 'hotfix' for SDK was released recently.
I havent tried it yet but sure hope that some annoying things will go away. "The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state" really is a mood killer. Hope for the best and upgrade here. (32 bit version also available here)



Dev Web Server for Azure Web Roles

clock January 27, 2011 22:17 by author Rok Bermež

Windows Azure uses 64 bit architecture so all dlls deployed to it must also be 64 bit. This poses significat development problem since 'Visual Studio Development Server'  and IIS Express run in 32 bit process. You can always use complete IIS, but it would be better if there was something more lightweight. It turns out there is. There is a nice project on codeplex called "CassiniDev - Cassini 3.5/4.0 Developers Edition" available here. Its binaries are also 32 bit so be sure to get the source and change Build platform target to either 'Any CPU' or 'x64'

  

and rebuild solution. After that just replace contents of 'C:\Program Files (x86)\Common Files\microsoft shared\DevServer\10.0' folder with your new freshly build 64 bit capable dev server

 



MVC3 Windows Azure Deployment

clock January 14, 2011 21:12 by author Rok Bermež

For RTM version of MVC 3 make sure the deployment contains following dlls:

  • Microsoft.Web.Infrastructure
  • System.Web.Helpers
  • System.Web.Mvc
  • System.Web.Razor
  • System.Web.WebPages
  • System.Web.WebPages.Deployment
  • System.Web.WebPages.Razor

 



About the author

Rok Bermež is Slovenian Windows Azure MVP, he works as a Software Engineer and Microsoft Certified Trainer at Kompas Xnet. His primary interests include cloud computing and web development. With extensive experience in development and architecture he participated in many projects and since the CTP release of Windows Azure much of those projects are based on Windows Azure platform. Rok has been delivering courses, writing code and speaking at conferences and community events on Microsoft technologies for the last couple of years. You can also find him on Twitter (@Rok_B).

Month List

Sign In