Syntax For Copying An Entire Directory To A New Directory In Azure Blog Storage Using AzCopy

July 20 2016

I wanted to copy every file from one directory to another using AzCopy. The cruz is using the /S switch which acts recursively. Here’s the syntax:

AzCopy /Source:https://sample.blob.core.windows.net/container/oldDir/

/Dest:https://c9hadoop.blob.core.windows.net/container/newDir/

/SourceKey:<key> /DestKey:<key> /S

Passing An Azure Staging Slot URI To A Test Runner In Visual Studio Team Services Release Management

July 12 2016

I wanted to run our coded ui tests using Selenium against the staging uri during our continuous integration workflow of our cloud service web role. But the problem arose that I didn’t know the dynamically generated URI that gets created by Azure when deploying to the staging slot.

I chatted with DevOps guru Thiago Almeida about this and he had the following suggestion:

Add a Powershell script between the publish step and the test step.  Here’s what the Powershell looked like:

$deployment = Get-AzureDeployment -ServiceName service_name -Slot Staging

if ($deployment -eq $null)

{

   write-host "No deployment is detected. "

   //Throw an exception for the build to fail here…

}

else

{

   $deploymentUrl = $deployment.Url

   # As explained here this next line creates a new variable with the value that other tasks can use https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md

   Write-Host ("##vso[task.setvariable variable=StagingWebsiteURL;]$deploymentUrl")

}

 

To use this, you’ll need to change the service_name to your Azure service name.

Then, on the Test Assemblies task’s “Override TestRun Parameters” value, update it to this to set the base URL to be the value of the variable set in the PowerShell task above:

webAppUrl=$(StagingWebsiteURL)

 

Nice! It totally worked! Tip of the hat to Thiago Almeida for suggesting this!

AzCopy Server to Server Transfer Is Awesome

July 12 2016

Just used AzCopy to move a bunch of files in blob storage accounts. So easy, so fast. Can’t recommend it enough! The documentation is really good on the website – highly recommended instead of writing your own code like I was going to have to do.

Why Did .NET Core Build A .dll and not an .exe?

June 16 2016

Started playing with .NET Core and, typical developer, didn’t read any docs first. Installed the tools, created a new project and typed Console.WriteLine(“Hello world.”).  And what did I get when I compiled? A .dll?  Weird. There was a public static void main(). What did I do wrong?

Well, I went and read some docs, in particular, this one: https://dotnet.github.io/docs/getting-started/cli-console-app-tutorial.html 

and I learned that you have to include a runtimes node to target execution environments, so I changed my project.json to include the runtime node in the project.json file like this:

{ "version": "1.0.0-*", "buildOptions": { "emitEntryPoint": true }, "dependencies": { "Microsoft.NETCore.App": { "version": "1.0.0-rc2-3002702" } }, "frameworks": { "netcoreapp1.0": { "imports": "dnxcore50" } }, "runtimes": { "win10-x64": {}, "osx.10.11-x64": {} } }

Well, my app didn’t compile! Why? Because I was running on Windows Server 2012, which requires the win8-x64 runtime. I added that so my runtime node looked like:

"runtimes": { "win8-x64": {}, "win10-x64": {}, "osx.10.11-x64": {} }

And, walla, my code compiled and a directory was generated with a .exe.  Hello world!

Using Visual Studio 2015 Project Templates and .NET Core

June 16 2016

Okay, this wasn’t entirely obvious: to get nifty project templates for .NET Core applications, you have to install both Visual Studio 2015 Update 2 (https://www.visualstudio.com/en-us/news/vs2015-update2-vs.aspx) and the .NET Core SDK for Windows (https://www.microsoft.com/net/core). Then you’ll see the templates for .NET Core when creating a new project.

Resolving the MSDeployPublish Error When Publishing Azure Web Jobs From Visual Studio 2015

April 22 2016

I had a rather old Azure web job that I always deployed by creating a .zip myself and uploading it to the portal manually. I decided to use the nice feature inside Visual Studio 2015 that publishes the project for you. But when I walked through the wizard and hit “publish” I received the following error:

Error MSB4057: The target "MSDeployPublish" does not exist in the project.

I realized a couple things. First, you have to add the Microsoft.Web.WebJobs.Publish.1.0.11 package from Nuget. Even though VS has the publish to Web Job action, it doesn’t automatically add that package to your project.  

Once you add it, you’re still screwed. VS doesn’t automatically modify your .csproj file to use this package. To do so, you need manually hack your .csproj file. Easiest way is to unload it in VS and add the following line right after the CSharp targets – I’ve included it below for context:

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

<Import Project="..\packages\Microsoft.Web.WebJobs.Publish.1.0.11\tools\webjobs.targets" Condition="Exists('..\packages\Microsoft.Web.WebJobs.Publish.1.0.11\tools\webjobs.targets')" />

With that, everything worked!

Note that I got into this whole scenario because for some mysterious reason, I could no longer successfully upload projects through either the legacy portal or the new one, so if you hit issue, my recommendation is to publish through VS, which is much cleaner anyway.

 

Using SSL in the Azure Compute Emulator With A Cloud Service Web Role

December 8 2015

Here's what I had to do to get SSL working in VS2015 with a web role in a cloud service:

 

1. Make sure that the url itself is 127.0.0.1 when launching IIS Express. If it is localhost, it won't work.

2. Make sure that you bind to the azure dev fabric thumbprint that gets installed with the SDK. If you are using the 2.7 SDK, it is F8ACE24A36F93B006BFAF495F6C14FB827AC61A3

3. Make sure that the dev fabric cert is in the right place. EG, if you say it is in "MY" then make sure it is Personal when you are looking in certificate manager. Or, if you say it in root, make sure you copy it there

I explicitly remove the HTTP endpoint as well.

I've attached a sample project that works.

AzureCloudService1.zip (425.21 kb)

Using NLog For Diagnostic Logging In Windows Azure Cloud Services And Writing The Logs To Azure Table Storage

November 6 2015

I’ve never liked the default logging mechanisms in Azure for application event logging.  Parsing the WADDiagnosticInfrastructureLogsTable is always such a hassle. Events I’ve written are mixed in with all the other events that Azure is firing all the time, and everything in my event is jammed into a single field.

So, for my current Azure project, I switched to using NLog and love it!  I used the NLog extension for writing events to Azure table storage: https://github.com/abkonsta/NLog.Extensions.AzureTableStorage – you’ll notice that isn’t the master Git repository, but the master one https://github.com/harouny/NLog.Extensions.AzureTableStorage doesn’t have the right README.md updated!  But I’m using 1.1.3.2 and it works great.

I am setting the connection string via code so that I pick up the string based on the local config or cloud config, aka

var azureStorageTarget = (AzureTableStorageTarget)
    LogManager.Configuration.FindTargetByName("AzureTableStorage");
azureStorageTarget.ConnectionString = RoleEnvironment.GetConfigurationSettingValue
    ("StorageConnectionString");
LogManager.ReconfigExistingLoggers();

 

And wow so much better. Some of the overloads are so nifty, like the ability to just give the exception to the logger, or letting the logger do the string formatting.  Nice!

Below is a sample project showing both a web role and a worker role using NLog and logging to table storage.

NLog4AzureCloudService.zip (495.15 kb)

Encrypting and Decrypting A String Sent As A Querystring Parameter Using C#

June 24 2015

I recently needed to encrypt/decrypt strings sent as querystring parameters over the wire. The use case happens to be allowing people to unsubscribe from a newsletter by clicking on a hyperlink in their email. The server receives the email as a querystring. Obviously, I don’t want to expose a public service that takes an unencrypted email. So, I encrypt the email as part of the newsletter template. Then decrypt on the web server.

Not rocket science, but worth going over how I did it, as there were a few gotchas.

First, I generated an RSA crypto key as XML, using the code found here:

public class MyCrypto
{
    RSACryptoServiceProvider rsa = null;
    string publicPrivateKeyXML;
    string publicOnlyKeyXML;
    public void AssignNewKey()
    {
        const int PROVIDER_RSA_FULL = 1;
        const string CONTAINER_NAME = "KeyContainer";
        CspParameters cspParams;
        cspParams = new CspParameters(PROVIDER_RSA_FULL);
        cspParams.KeyContainerName = CONTAINER_NAME;
        cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
        cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
        rsa = new RSACryptoServiceProvider(cspParams);
 
        //Pair of public and private key as XML string.
        //Do not share this to other party
        publicPrivateKeyXML = rsa.ToXmlString(true);
 
        //Private key in xml file, this string should be share to other parties
        publicOnlyKeyXML = rsa.ToXmlString(false);
         
    }
}

Then, to encrypt the string in such a way that it could be passed as a querystring, I had to make some changes. First, I changed the encoding to UTF8 and not ASCII. Second, I then base64 encode the string, Third, I URL encode the string:

public string EncryptAndEncode(string text)
{
    string encryptedText;
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
        rsa.FromXmlString(Resources.Resources.publicKeyXML);
        var bytes = rsa.Encrypt(Encoding.UTF8.GetBytes(text), true);
        encryptedText = Convert.ToBase64String(bytes);
    }
    return HttpUtility.UrlEncode(encryptedText);
}

On the decrypt side, because I’m getting the string as a method in my controller, the URL decoding is handled for me. So, the decrypt looks like this:

private string Decrypt(string text)
{
    string decryptedText;
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
        rsa.FromXmlString(Resources.Resources.publicPrivateKeyXML);
        var bytes = Convert.FromBase64String(text);
        decryptedText = Encoding.UTF8.GetString(rsa.Decrypt(bytes, true));
    }
    return decryptedText;
}

Installing Blog Engine 3.1 As A Virtual Application Under An MVC Website With Sql Server

May 14 2015

Hit a bunch of gotchas doing this; figure I’d share with the world how I got it working.

1. RUN THE UPDATED SQL SCRIPT

There’s a piece of SQL script that isn’t in the setup script and can only be found if you download the source … or copy/paste from below :)

ALTER TABLE dbo.be_Pages ADD
    SortOrder int NOT NULL CONSTRAINT DF_be_Pages_SortOrder DEFAULT 0
GO
CREATE NONCLUSTERED INDEX IX_be_Pages ON dbo.be_Pages
    (
    SortOrder
    ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

2. BEWARE WEB.CONFIG INHERITANCE

Because of web.config inheritance from the root application, all kinds of wacky stuff can go wrong. Easiest fix is to turn off inheritInChildApplications like this:

 

<location path="." inheritInChildApplications="false">
<system.web>
...
</system.web>
</location>

Remember to do it from system.web and system.webserver. And for appsettings, unless you do #3 below.

3. ADD SOME APPSETTINGS

Even if you add that element to appSettings, you still may need to add the following appSettings:

<appSettings>
  <add key="webpages:Enabled" value="true" />
  <add key="webpages:Version" value="3.0.0.0" />
...
</appSettings>

4. CONFIGURE MEMBERSHIP AND ROLEMANAGER

If you are using Sql Server, of course you change the provider up at the top of web.config.

<BlogEngine>
   <blogProvider defaultProvider="DbBlogProvider" fileStoreProvider="DbBlogProvider">
...
    </blogProvider>
</BlogEngine>

But don’t forget to configure membership and roleManager to use the database. They are deeper down in web.config:

<membership defaultProvider="DbMembershipProvider">
  <providers>
    <clear />
    <add name="XmlMembershipProvider" type="BlogEngine.Core.Providers.XmlMembershipProvider, BlogEngine.Core" description="XML membership provider" passwordFormat="Hashed" />
    <add name="SqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="BlogEngine" applicationName="BlogEngine" />
    <add name="DbMembershipProvider" type="BlogEngine.Core.Providers.DbMembershipProvider, BlogEngine.Core" passwordFormat="Hashed" connectionStringName="BlogEngine" />
  </providers>
</membership>
<roleManager defaultProvider="DbRoleProvider" enabled="true" cacheRolesInCookie="false">
  <providers>
    <clear />
    <add name="XmlRoleProvider" type="BlogEngine.Core.Providers.XmlRoleProvider, BlogEngine.Core" description="XML role provider" />
    <add name="SqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="BlogEngine" applicationName="BlogEngine" />
    <add name="DbRoleProvider" type="BlogEngine.Core.Providers.DbRoleProvider, BlogEngine.Core" connectionStringName="BlogEngine" />
  </providers>
</roleManager>

5. ADD A TRAILING SLASH WHEN YOU GO TO THE ADMIN

There’s a problem with the routing in the admin and you’ll get a blank page if you don’t add a trailing slash, aka http://locahost/blog/admin/ 

 

With those fixes, you should be able to get the best blogging platform written in .NET up and running!