1

I have an azure cloud service which I am attempting to upgrade for high availability and I have subscribed to the Microsoft Azure File Service preview which has been enabled in the preview portal. I have created a new storage account and can see the storage account now has a Files endpoint located at:

https://<account-name>.file.core.windows.net/

Within my web role I have the following code which looks to see if a share called scorm is created and if not it creates it:

public static void CreateCloudShare()
{
    CloudStorageAccount account = CloudStorageAccount.Parse(System.Configuration.ConfigurationManager.AppSettings["SecondaryStorageConnectionString"].ToString());
    CloudFileClient client = account.CreateCloudFileClient();
    CloudFileShare share = client.GetShareReference("scorm");
    share.CreateIfNotExistsAsync().Wait();
}

This works without issue. My problem is that I am unsure as to how to map the CloudShare that has been created as a virtual directory within my cloud service. On a single instance I was able to do this:

public static void CreateVirtualDirectory(string VDirName, string physicalPath)
{
    try
    {

        if (VDirName[0] != '/')
            VDirName = "/" + VDirName;

        using (var serverManager = new ServerManager())
        {
            string siteName = RoleEnvironment.CurrentRoleInstance.Id + "_" + "Web";
            //Site theSite = serverManager.Sites[siteName];
            Site theSite = serverManager.Sites[0];
            foreach (var app in theSite.Applications)
            {
                if (app.Path == VDirName)
                {
                    // already exists
                    return;
                }
            }
            Microsoft.Web.Administration.VirtualDirectory vDir = theSite.Applications[0].VirtualDirectories.Add(VDirName, physicalPath);
            serverManager.CommitChanges();
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.EventLog.WriteEntry("Application", ex.Message, System.Diagnostics.EventLogEntryType.Error);
        //System.Diagnostics.EventLog.WriteEntry("Application", ex.InnerException.Message, System.Diagnostics.EventLogEntryType.Error);
    }
}

I have looked and seen that it is possible to map this via powershell but I am unsure as to how I could call the code within my web role. I have added the following method to run the powershell code:

public static int ExecuteCommand(string exe, string arguments, out string error, int timeout)
{
    Process p = new Process();
    int exitCode;
    p.StartInfo.FileName = exe;
    p.StartInfo.Arguments = arguments;
    p.StartInfo.CreateNoWindow = true;
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardError = true;
    p.Start();
    error = p.StandardError.ReadToEnd();
    p.WaitForExit(timeout);
    exitCode = p.ExitCode;
    p.Close();

    return exitCode;
}

I know that the command I have to run is:

net use z: \\<account-name>.file.core.windows.net\scorm /u:<account-name> <account-key>

How can I use this from within my web role? My web role code is as follows but does not seem to be working :

public override bool OnStart()
{
    try
    {

        CreateCloudShare();
        ExecuteCommand("net.exe", "user " + userName + " " + password + " /add", out error, 10000);
        ExecuteCommand("netsh.exe", "firewall set service type=fileandprint mode=enable scope=all", out error, 10000);
        ExecuteCommand("net.exe", " share " + shareName + "=" + path + " /Grant:" + userName + ",full", out error, 10000);

    }
    catch (Exception ex)
    {
        System.Diagnostics.EventLog.WriteEntry("Application", "CREATE CLOUD SHARE ERROR : " + ex.Message, System.Diagnostics.EventLogEntryType.Error);
    }
    return base.OnStart();
}
Jay
  • 3,012
  • 14
  • 48
  • 99

2 Answers2

2

Our blog post Persisting connections to Microsoft Azure Files has an example of referencing Azure Files shares from web and worker roles. Please see the "Windows PaaS Roles" section and also take a look at the note under "Web Roles and User Contexts".

Serdar Ozler
  • 3,752
  • 17
  • 24
  • Where do I put the WNetAddConnection2 code? Does this go in global.asax? – Jay Jul 31 '14 at 09:35
  • Correct, it will be in Global. – Serdar Ozler Jul 31 '14 at 23:45
  • Brilliant got it working thank you so much for the excellent blog Serdar greatly appreciated I had some issues with disconnected drives not being cleaned in explorer. Note that when you do get this working for the PaaS it will not be available in the list of mappings in explorer for your remote user – Jay Aug 01 '14 at 13:39
1

The library RedDog.Storage makse it really easy to mount a drive in your Cloud Service without having to worry about P/Invoke:

Install-Package RedDog.Storage

After the package is installed, you can simply use the extension method "Mount" on your CloudFileShare:

public class WebRole : RoleEntryPoint
{
    public override bool OnStart()
    {
        // Mount a drive.
        FilesMappedDrive.Mount("P:", @"\\acc.file.core.windows.net\reports", "sandibox", 
            "key");

        // Unmount a drive.
        FilesMappedDrive.Unmount("P:");

        // Mount a drive for a CloudFileShare.
        CloudFileShare share = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"))
            .CreateCloudFileClient()
            .GetShareReference("reports");
        share.Mount("P:");

        // List drives mapped to an Azure Files share.
        foreach (var mappedDrive in FilesMappedDrive.GetMountedShares())
        {
            Trace.WriteLine(String.Format("{0} - {1}", mappedDrive.DriveLetter, mappedDrive.Path));
        }

        return base.OnStart();
    }
}

More information: http://fabriccontroller.net/blog/posts/using-the-azure-file-service-in-your-cloud-services-web-roles-and-worker-role/

Sandrino Di Mattia
  • 24,739
  • 2
  • 60
  • 65