locked
Uploading a local image to my website using FTP RRS feed

  • Question

  • User1434241939 posted

    I am trying to let people upload files from their machines to my website via FTP.  I am successfully able to do this while debugging from Visual Studio.  However when I deploy to the web, I get an error thrown from File.ReadAllBytes:

            public void UploadFile(String filename) 
            {
                if (filename != null)
                {
                    //string sourcePath = "C:/airsick/100 dpi with no matching 300 dpi scans/" +
                    //    filename.Substring(0, 1) + "/";
                    string sourcePath = @"C:\airsick\100 dpi with no matching 300 dpi scans\" +
                        filename.Substring(0, 1) + @"\";
                    string targetPath = @"wwwroot\images\";
    
    
    
                    // Get the object used to communicate with the server.
                    // ** Credentials removed **
                    FtpWebRequest request = (FtpWebRequest)WebRequest
                        .Create("ftp://X.X.X.X/mvc.fitpacking.com/wwwroot/images/" + filename + ".jpg");
                    request.Method = WebRequestMethods.Ftp.UploadFile;
                    request.UsePassive = false;
                    request.UseBinary = true;
    
                    //// FTP login
                    string pass = Environment.GetEnvironmentVariable("FTP_ACCESS");
                    request.Credentials = new NetworkCredential("username", pass);
    
                    // Copy the contents of the file.  IMAGE FILES ONLY
                    byte[] fileContents = File.ReadAllBytes(sourcePath + filename + ".jpg");  // THIS THROWS AN ERROR WHEN DEPLOYED
                    request.ContentLength = fileContents.Length;
    
                    Stream requestStream = request.GetRequestStream();
                    requestStream.Write(fileContents, 0, fileContents.Length);
                    requestStream.Close();
    
                    FtpWebResponse response = (FtpWebResponse)request.GetResponse();
    
                    response.Close();
    
                }
    
            }
    

    I am aware that the hardcoded path is specific to my machine and Windows OS (although it might work in Linux too).  My guess is that there's some kind of security setting that won't allow a website access to a local file on my machine.

    Yet this seems like a common item that has been coded thousands of times.  What am I missing?

    Sunday, December 6, 2020 4:38 PM

Answers

  • User753101303 posted

    Hi,

    stevebo

    My guess is that there's some kind of security setting that won't allow a website access to a local file on my machine.

    This is C# code that runs on a web server and the web server just doesn't have access at all to the client side drive (unless the very special case where your developement machine is both the web server and the browser client side).

    If you want to use FTP, the user would have to use its own FTP client side software to upload this file.

    If this is for end users, the common option is to upload files using the browser and the input type="file" tag: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file

    What to do on the server side depends if you are using Web Forms or MVC with ASP.NET 4.x or ASP.NET Core.

    Edit: from your code seems ASP.NET Core so you could try  https://www.aspsnippets.com/Articles/Using-IFormFile-in-ASPNet-Core.aspx

    Note also that if reusing the client side filename unchanged to save the file on the server side, one user could override the file upload by someone else. Most often I prefer to keep the original file name in the db (if useful later) and name the file with my own name (for example a guid) to avoid any collision.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, December 7, 2020 10:48 AM

All replies

  • User-939850651 posted

    Hi stevebo,

    I am aware that the hardcoded path is specific to my machine and Windows OS (although it might work in Linux too).  My guess is that there's some kind of security setting that won't allow a website access to a local file on my machine.

    This may also exist in the situation you described, or it may be due to other reasons.

    Could you get the relevant error log messages? I think you can get more clear information from the log and find a suitable solution for this.

    Best regards,

    Xudong Peng

    Monday, December 7, 2020 10:26 AM
  • User753101303 posted

    Hi,

    stevebo

    My guess is that there's some kind of security setting that won't allow a website access to a local file on my machine.

    This is C# code that runs on a web server and the web server just doesn't have access at all to the client side drive (unless the very special case where your developement machine is both the web server and the browser client side).

    If you want to use FTP, the user would have to use its own FTP client side software to upload this file.

    If this is for end users, the common option is to upload files using the browser and the input type="file" tag: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file

    What to do on the server side depends if you are using Web Forms or MVC with ASP.NET 4.x or ASP.NET Core.

    Edit: from your code seems ASP.NET Core so you could try  https://www.aspsnippets.com/Articles/Using-IFormFile-in-ASPNet-Core.aspx

    Note also that if reusing the client side filename unchanged to save the file on the server side, one user could override the file upload by someone else. Most often I prefer to keep the original file name in the db (if useful later) and name the file with my own name (for example a guid) to avoid any collision.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, December 7, 2020 10:48 AM
  • User1434241939 posted

    If this is for end users, the common option is to upload files using the browser and the input type="file" tag:

    I abandoned FTP in favor of the file method and it works great on my local machine.  However, when I deploy to my ISP I get a NullReferenceException (see entire error below).  

    Here is the code that I'm using in my controller:

                        foreach(var file in files)
                        {
                            if (file != null || file.Length != 0)
                            {
    
                                String path = Path.Combine(
                                            Directory.GetCurrentDirectory(), "wwwroot\\images",
                                            file.FileName);
    
    
                                using (var stream = new FileStream(path, FileMode.Create))
                                {
                                    await file.CopyToAsync(stream);
                                }
    
                            }
                        }

    I have hacked this up for several different values of path -- all of which give the NullReferenceException on the new FileStream -- including:

    ~/wwwroot/images/Sterling2008A.jpg
    ./wwwroot/images/Sterling2008A.jpg
    Sterling2008A.jpg
    D:\InetPub\vhosts\fitpacking.com\mvc.fitpacking.com\wwwroot\images\Sterling2008A.jpg

    I have spent many hours on this with no real understanding of what's wrong.  I have no real access to my ISP's server.  FTP seems to be the most reliable way for me to communicate with it.  Any help appreciated.

    Here's the full error:

    An unhandled exception occurred while processing the request.
    NullReferenceException: Object reference not set to an instance of an object.
    AspNetCore.Views_Bags_Edit+<>c__DisplayClass28_0+<<ExecuteAsync>b__0>d.MoveNext() in Edit.cshtml, line 16
     
    Stack Query Cookies Headers Routing
    NullReferenceException: Object reference not set to an instance of an object.
    AspNetCore.Views_Bags_Edit+<>c__DisplayClass28_0+<<ExecuteAsync>b__0>d.MoveNext() in Edit.cshtml
    Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.GetChildContentAsync(bool useCachedResult, HtmlEncoder encoder)
    Microsoft.AspNetCore.Mvc.TagHelpers.RenderAtEndOfFormTagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
    Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.<RunAsync>g__Awaited|0_0(Task task, TagHelperExecutionContext executionContext, int i, int count)
    AspNetCore.Views_Bags_Edit.ExecuteAsync() in Edit.cshtml
    Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
    Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, bool invokeViewStarts)
    Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
    Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
    Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
    Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, string contentType, Nullable<int> statusCode)
    Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
    Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
    Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0<TFilter, TFilterAsync>(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
    Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
    Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
    Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
    Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
    Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
    Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
    Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
    Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
    Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
    Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
    Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
    Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
    Monday, December 7, 2020 10:21 PM
  • User753101303 posted

    It seems rather to happen in Edit.cshtml?

    FTP require the use of a client side FTP software and is still used by developers or tech savy people. If you want to allows app users to upload files it's likely best to provide them that right from the browser they are already using.

    Monday, December 7, 2020 11:58 PM
  • User1434241939 posted

    I want to apologize for wasting your time with this, but in desperation I contacted my ISP's tech support and they fixed it!  There was nothing wrong with the code, they just had security settings too restrictive so that nobody could not upload any files via <form type="file"> tag.

    Thank you for getting me away from FTP and helping me get this fixed even if there was nothing we could do without my hosting company's intervention.

    Wednesday, December 9, 2020 9:33 AM