1

I have an Azure VM with IIS setup, which hosts my ASP.Net website.

I want to be able to read and write documents/files from a network share (Azure file storage) by using the normal windows class libraries (System.IO). I do not want to use the Azure storage client libraries nor the Azure Storage Rest API.

I have mounted the share and persisted my credentials as detailed in this article.

After mounting the drive and persisting my credentials, I point my website to make use of my shared drive for all document management related functions. Downloading a file works perfectly. I receive an error, however, as soon as I try to create a folder or write a document to the network share.

The error I receive is:

Could not find a part of the path 'F:[RestOfThePathHere]'. Stack Trace:

[DirectoryNotFoundException: Could not find a part of the path 'F:\Test\MyThing\Clients\TheirStuff'.]
System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) +338 System.IO.Directory.InternalCreateDirectory(String fullPath, String path, Object dirSecurityObj, Boolean checkHost) +1578
System.IO.Directory.InternalCreateDirectoryHelper(String path, Boolean checkHost) +213
MyStuff.FileHandling.FileExtenders.SaveToFile(Byte[] ByteArray, String Directory, String FileName) +116
MyStuff.TheirStuff.BLL.TheirStuffTestClient.RunEnquiry(ClientBase client, String resultType) +3776
MyStuff.MyThing.UI.Views.ClientController.CreditCheck(Int64 id) +42
lambda_method(Closure , ControllerBase , Object[] ) +114
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary2 parameters) +242
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary
2 parameters) +39
System.Web.Mvc.Async.AsyncControllerActionInvoker.b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +12
System.Web.Mvc.Async.WrappedAsyncResult2.CallEndDelegate(IAsyncResult asyncResult) +139
System.Web.Mvc.Async.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d() +112 System.Web.Mvc.Async.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() +452 System.Web.Mvc.Async.<>c__DisplayClass33.<BeginInvokeActionMethodWithFilters>b__32(IAsyncResult asyncResult) +15
System.Web.Mvc.Async.<>c__DisplayClass2b.<BeginInvokeAction>b__1c() +37 System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult) +241
System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +29
System.Web.Mvc.Async.WrappedAsyncVoid
1.CallEndDelegate(IAsyncResult asyncResult) +111
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53 System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +19
System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +51
System.Web.Mvc.Async.WrappedAsyncVoid
1.CallEndDelegate(IAsyncResult asyncResult) +111
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +606 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288

OR, when I use UNC addressing

The network path was not found. StackTrace: [IOException: The network path was not found. ]
System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) +14382132 System.IO.Directory.InternalCreateDirectory(String fullPath, String path, Object dirSecurityObj, Boolean checkHost) +1578 System.IO.Directory.InternalCreateDirectoryHelper(String path, Boolean checkHost) +213
MyStuff.FileHandling.FileExtenders.SaveToFile(Byte[] ByteArray, String Directory, String FileName) +116
MyStuff.TheirStuff.BLL.TheirStuffTestClient.RunEnquiry(ClientBase client, String resultType) +3776
MyStuff.MyThing.UI.Views.ClientController.CreditCheck(Int64 id) +42
lambda_method(Closure , ControllerBase , Object[] ) +114
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary2 parameters) +242
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary
2 parameters) +39
System.Web.Mvc.Async.AsyncControllerActionInvoker.b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +12
System.Web.Mvc.Async.WrappedAsyncResult2.CallEndDelegate(IAsyncResult asyncResult) +139
System.Web.Mvc.Async.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d() +112 System.Web.Mvc.Async.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() +452 System.Web.Mvc.Async.<>c__DisplayClass33.<BeginInvokeActionMethodWithFilters>b__32(IAsyncResult asyncResult) +15
System.Web.Mvc.Async.<>c__DisplayClass2b.<BeginInvokeAction>b__1c() +37 System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult) +241
System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +29
System.Web.Mvc.Async.WrappedAsyncVoid
1.CallEndDelegate(IAsyncResult asyncResult) +111
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53 System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +19
System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +51
System.Web.Mvc.Async.WrappedAsyncVoid
1.CallEndDelegate(IAsyncResult asyncResult) +111
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +606 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288

Update - My current code

MVC Controller Method

public ActionResult Upload(DocumentUploadVM VM, long ClientId, long ContextInstanceId, long DocumentClassId, long TaskId)
    {
            var documentClass = docMan.Get_DocumentClass(DocumentClassId);

            var errors = new List<string>();

            if (VM.File == null || VM.File.ContentLength == 0)
                errors.Add("You haven't selected a file to upload");
            else if (!documentClass.MimeTypeAllowed(VM.File.ContentType, docMan))
                errors.Add("The file type is forbidden");

            if (errors.Count == 0 && ModelState.IsValid)
            {
                var path = settings.GetSettingValueAsString("Document Management: Client Documents Root Path").TrimEnd('\\') + "\\Uploads\\";
                var pvtFileName = new Random().Next().ToString() + "." + VM.File.FileName.Split('.').Last();
                var targetURI = Path.Combine(path, pvtFileName);

                MemoryStream ms = new MemoryStream();
                VM.File.InputStream.CopyTo(ms);

                IFileHandler fh = FileHandlingFactory.Create();
                fh.SaveFile(ms, targetURI);

                docMan.Add_Document(
                    new FileItem
                    {
                        FilePathOnServer = path,
                        PublicFileName = VM.File.FileName,
                        PrivateFileName = pvtFileName,
                        MimeType = VM.File.ContentType
                    },
                    docMan.Get_ContextInstance(ContextInstanceId),
                    new List<DocumentClass> { documentClass });
            }
            else
            {
                TempData["errors"] = errors;
            }

            //TODO: In case of model errors, this call will suppress the errors.  Look to TempData / PRG pattern to maintain model state over redirect.
            return
              RedirectToAction("ListClientDocuments", new { ClientId = ClientId, TaskId = TaskId });
        }

IFileHandler.SaveFile implementation

public override void SaveFile(MemoryStream MemoryStream, string Fullpath)
    {
        var directory = Fullpath.Substring(0, Fullpath.LastIndexOf('\\')).TrimEnd('\\');
        var fileName = Fullpath.Replace(directory, "").Trim('\\');
        MemoryStream.ToArray()
        .SaveToFile(directory, fileName);
    }

PS - Please excuse the terrible code and blatant disregard for C# coding standards. I was a noob when I wrote this. However, this code has not yet given me any problems when used to address local file-storage.

CShark
  • 2,183
  • 1
  • 24
  • 42
  • It would help to see the relevant code used to establish the connection and attempt the file access/creation. Redact anything private of course. – Byron Jones Feb 01 '16 at 20:21
  • Did you use "net use"? "Net use" is relative to the user from which you run "net use". So you web application will not see it (unless you run the web-app with the same user). – Fabrizio Accatino Feb 02 '16 at 08:11
  • @FabrizioAccatino Yes, I used "net use", and I did not log in with the same user with which I run the web app. Is there any other way I can achieve this with my default iis user? – CShark Feb 02 '16 at 11:01
  • 1
    @CraftBeerHipsterDude I think that you have to use a "net use by code". Something like http://stackoverflow.com/questions/5433570/access-a-remote-directory-from-c-sharp – Fabrizio Accatino Feb 02 '16 at 13:27
  • @ByronJones Code added as requested – CShark Feb 02 '16 at 21:14
  • @FabrizioAccatino I have implemented the code you referenced but I am still receiving the same errors. – CShark Feb 04 '16 at 17:14

1 Answers1

1

I think you may want try create a local user that maps to the storage account user and then add this user to IIS_IUSRS group.

Please refer to this blog for details http://blogs.iis.net/davidso/azurefile

-Jason

  • 2
    Thanks for the answer. I really do wish MS would make it easier for us to host our websites as Azure websites and not VMs, without having to resort to specialist API's for SMB file storage (in other words, using normal System.IO for reading and writing to shared storage). – CShark Feb 09 '16 at 20:24
  • Did this actually work? For some reason I cant get that article to work. – Mike Flynn Feb 13 '16 at 05:40
  • OMG - thank you SO MUCH for this response.Totally made my day! ✨ – Alexander Marek Apr 16 '19 at 06:56