Search code examples
c#asp.net-web-api2fileinfovirtual-path

Why is the map.server virtual path not being saved to the database


I have been stuck on saving the virtual path of a file upload to my db. Without the virtual path the file is being saved and the url in the db is the physical path of the file. so when i try to download it I am getting the local resource not allowed. the url starts with file:///C:path....
When i use break points I see that the physical path is being changed to the virtual path, however it exceptions out.

apiController

//POST
    public async Task<HttpResponseMessage> Post()
    {

        try
        {
            //saving the posted file to the harddisk
            string root = HttpContext.Current.Server.MapPath("~/Files/");
            var provider = new MultipartFormDataStreamProvider(root);
            await Request.Content.ReadAsMultipartAsync(provider);

            //Get Logged in User Name
            var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
            var user = manager.FindById(User.Identity.GetUserId());

            //getting the user details and storing in the object
            Document model = new Document();
            model.TypeId = Convert.ToInt32(provider.FormData["TypeId"]);
            model.TypeName = provider.FormData["TypeName"];
            model.PipeName = provider.FormData["PipeName"];
            model.DocumentUrl = provider.FormData["DocumentUrl"];
            model.DocumentUrl = model.DocumentUrl == "" ? null : model.DocumentUrl;

            //if there is a file then save that file to the desired location
            if (provider.FileData.Count > 0)
            {
                MultipartFileData fileData = provider.FileData[0];
                FileInfo fi = new FileInfo(fileData.LocalFileName);
                if (!Directory.Exists(fi.DirectoryName))
                {
                    Directory.CreateDirectory(fi.DirectoryName);
                }
                else
                {
                    //getting the file saving path
                    string clientFileName = fileData.Headers.ContentDisposition.FileName.Replace(@"""", "");
                    if (clientFileName != "")
                    {
                        string clientExtension = clientFileName.Substring(clientFileName.LastIndexOf('.'));
                        string space = ("-");
                        var dt = model.DocumentDate.ToString("y").Replace('/', '-').Replace(':', '-');
                        var CompanyName = model.CompanyName.Replace('_', ' ');

                        string vPath = root.Replace(@"C:\Development\TransparentEnergy\TransparentEnergy", "~").Replace("\\", "/");
                        string serverFileName = vPath + CompanyName + space + model.TypeName + space + model.CounterPartyName + space + dt + clientExtension;
                        model.DocumentUrl = serverFileName;



                        FileInfo fiOld = new FileInfo(vPath);
                        if (fiOld.Exists)
                            fiOld.Delete();
                        //if (File.Exists())
                        fi.MoveTo(serverFileName);
                    }
                    else
                    {
                        if (fi.Exists)
                            fi.Delete();
                    }
                }
            }
            //calling DB to save the user details
            using (var context = new ApplicationDbContext())
            {
                //save to db
                context.Documents.Add(model);
                context.SaveChanges();
            }
        }
        catch (Exception fex)
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, fex);
        }
        //sending the confirmation or error back to the user
        return Request.CreateResponse(HttpStatusCode.OK);
    }

The breakpoint at :

model.DocumentUrl = serverFileName;

shows

"~/Files/Black Elk-Invoices-None-May 2006.pdf"

The Exception happens here

 FileInfo fiOld = new FileInfo(vPath);
  if (fiOld.Exists)
  fiOld.Delete();
//if (File.Exists())
  fi.MoveTo(serverFileName);

The FiloInfo(vPath) shows

~/Files/

The Exception happens at :

fi.MoveTo(serverFileName);

Exception message:

at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.__Error.WinIOError() at System.IO.FileInfo.MoveTo(String destFileName) at TransparentEnergy.ControllersAPI.apiInvoiceController.d__0.MoveNext() in c:\Development\TransparentEnergy\TransparentEnergy\ControllersAPI\SubmitApi\apiInvoiceController.cs:line 87

Updated

 //POST
    public async Task<HttpResponseMessage> Post()
    {

        try
        {
            //saving the posted file to the harddisk
            string root = HttpContext.Current.Server.MapPath("~/Files/");
            var provider = new MultipartFormDataStreamProvider(root);
            await Request.Content.ReadAsMultipartAsync(provider);

            //Get Logged in User Name
            var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
            var user = manager.FindById(User.Identity.GetUserId());

            //getting the user details and storing in the object
            Document model = new Document();
            model.TypeId = Convert.ToInt32(provider.FormData["TypeId"]);
            model.TypeName = provider.FormData["TypeName"];
            model.LocationId = Convert.ToInt32(provider.FormData["LocationId"]);
            model.LocationName = provider.FormData["LocationName"];
            model.PipeId = Convert.ToInt32(provider.FormData["PipeId"]);
            model.PipeName = provider.FormData["PipeName"];
            model.CompanyId = Convert.ToInt32(provider.FormData["CompanyId"]);
            model.CompanyName = provider.FormData["CompanyName"];
            model.PlantId = Convert.ToInt32(provider.FormData["PlantId"]);
            model.PlantName = provider.FormData["PlantName"];
            model.CounterPartyId = Convert.ToInt32(provider.FormData["CounterPartyId"]);
            model.CounterPartyName = provider.FormData["CounterPartyName"];
            string docDate = provider.FormData["DocumentDate"];
            model.DocumentDate = DateTime.Parse(docDate.Trim('"'));
            model.UploadedBy = user.Name;
            model.UploadDate = DateTime.Now;
            model.DocumentUrl = provider.FormData["DocumentUrl"];

            //if there is a file then save that file to the desired location
            if (provider.FileData.Count > 0)
            {
                MultipartFileData fileData = provider.FileData[0];
                FileInfo fi = new FileInfo(fileData.LocalFileName);

                //getting the file saving path
                string clientFileName = fileData.Headers.ContentDisposition.FileName.Replace(@"""", "");
                if (clientFileName != "")
                {
                    string clientExtension = clientFileName.Substring(clientFileName.LastIndexOf('.'));
                    string dash = ("-");
                    var dt = model.DocumentDate.ToString("y").Replace('/', '-').Replace(':', '-');
                    var CompanyName = model.CompanyName.Replace('_', ' ');

                    string vPath = root.Replace(@"C:\Development\TransparentEnergy\TransparentEnergy", "~").Replace("\\", "/");
                    string path = String.Format(CompanyName + dash + model.TypeName + dash + model.CounterPartyName + dash + dt + clientExtension);

                    string combination = Path.Combine(vPath, path);
                    model.DocumentUrl = combination;
                    FileInfo fiOld = new FileInfo(path);
                    if (fiOld.Exists)
                        fiOld.Delete();
                    //if (File.Exists())
                    fi.MoveTo(vPath);
                }
                else
                {
                    if (fi.Exists)
                        fi.Delete();
                }

            }
            //calling DB to save the user details
            using (var context = new ApplicationDbContext())
            {
                //save to db
                context.Documents.Add(model);
                context.SaveChanges();
            }
        }
        catch (Exception fex)
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, fex);
        }
        //sending the confirmation or error back to the user
        return Request.CreateResponse(HttpStatusCode.OK);
    }

This Works!

 public async Task<HttpResponseMessage> Post()
    {

        try
        {
            //saving the posted file to the harddisk
            //string root = HttpContext.Current.Server.MapPath("~/Files/");
            string root = HostingEnvironment.MapPath(ConfigurationManager.AppSettings["~/Files/"]);
            var provider = new MultipartFormDataStreamProvider(root);
            await Request.Content.ReadAsMultipartAsync(provider);

            //Get Logged in User Name
            var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
            var user = manager.FindById(User.Identity.GetUserId());

            //getting the user details and storing in the object
            Document model = new Document();
            model.TypeId = Convert.ToInt32(provider.FormData["TypeId"]);
            model.TypeName = provider.FormData["TypeName"];
            model.LocationId = Convert.ToInt32(provider.FormData["LocationId"]);
            model.LocationName = provider.FormData["LocationName"];
            model.PipeId = Convert.ToInt32(provider.FormData["PipeId"]);
            model.PipeName = provider.FormData["PipeName"];
            model.CompanyId = Convert.ToInt32(provider.FormData["CompanyId"]);
            model.CompanyName = provider.FormData["CompanyName"];
            model.PlantId = Convert.ToInt32(provider.FormData["PlantId"]);
            model.PlantName = provider.FormData["PlantName"];
            model.CounterPartyId = Convert.ToInt32(provider.FormData["CounterPartyId"]);
            model.CounterPartyName = provider.FormData["CounterPartyName"];
            string docDate = provider.FormData["DocumentDate"];
            model.DocumentDate = DateTime.Parse(docDate.Trim('"'));
            model.UploadedBy = user.Name;
            model.UploadDate = DateTime.Now;
            model.DocumentUrl = provider.FormData["DocumentUrl"];

            //if there is a file then save that file to the desired location
            if (provider.FileData.Count > 0)
            {
                MultipartFileData fileData = provider.FileData[0];
                FileInfo fi = new FileInfo(fileData.LocalFileName);

                //getting the file saving path
                string clientFileName = fileData.Headers.ContentDisposition.FileName.Replace(@"""", "");
                if (clientFileName != "")
                {
                    string clientExtension = clientFileName.Substring(clientFileName.LastIndexOf('.'));

                    var dt = model.DocumentDate.ToString("y").Replace('/', '-').Replace(':', '-');
                    var CompanyName = model.CompanyName.Replace('_', ' ');

                    string vPath = root.Replace(@"C:\Development\TransparentEnergy\TransparentEnergy", "~").Replace("\\", "/");
                    string fileName = String.Format("{0}-{1}-{2}-{3}{4}", CompanyName, model.TypeName, model.CounterPartyName, dt, clientExtension);
                    string combination = Path.Combine(vPath, fileName);
                    model.DocumentUrl = combination;

                    string physicalPath = HttpContext.Current.Server.MapPath("/Files");
                    string relativePath = Path.Combine(physicalPath, fileName);
                    FileInfo fiOld = new FileInfo(relativePath);
                    if (fiOld.Exists)
                        fiOld.Delete();
                    //if (File.Exists())
                    fi.MoveTo(relativePath);
                }
                else
                {
                    if (fi.Exists)
                        fi.Delete();
                }

            }
            //calling DB to save the user details
            using (var context = new ApplicationDbContext())
            {
                //save to db
                context.Documents.Add(model);
                context.SaveChanges();
            }
        }
        catch (Exception fex)
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, fex);
        }
        //sending the confirmation or error back to the user
        return Request.CreateResponse(HttpStatusCode.OK);
    }

Solution

  • I suspect your issue happens because the (badly named) serverFileName in fi.MoveTo(serverFileName); actually points to a virtual path instead of to a physical path.

    Note that I'd really advise to rethink your code. Some examples:

    • string space = ("-");: "-" isn't a space.
    • model.DocumentDate.ToString("y").Replace('/', '-').Replace(':', '-'); looks like a bad way to format a date.
    • string serverFileName = vPath + CompanyName + space + model.TypeName + space + model.CounterPartyName + space + dt + clientExtension; First, use Path.Combine to join a folder and a filename. Second, wouldn't it be better to use string.Format to create the name of the file instead of a long concatenation? Third, serverFileName is IMHO a bad name, I'd call this a path.
    • I really don't get what is happening with model.DocumentUrl: first it gets the value of provider.FormData["DocumentUrl"], then you check if model.DocumentUrl is an empty string (note that it is preferred to use string.Empty) and set it to NULL if that's the case, and then you assign it serverFileName.