1

I have some files in my wwwroot folder. I want to write a code that user click on input button and download file that he wants. So filename is unknown until user select his file.

I wrote this code:

Profile Controller:

    public async Task<IActionResult> Download(string filename)
    {
        if (filename == null)
            return Content("filename not present");

        var path = Path.Combine(
                       Directory.GetCurrentDirectory(),
                       "wwwroot", filename);

        var memory = new MemoryStream();
        using (var stream = new FileStream(path, FileMode.Open))
        {
            await stream.CopyToAsync(memory);
        }
        memory.Position = 0;
        return File(memory, GetContentType(path), Path.GetFileName(path));
    }

    private string GetContentType(string path)
    {
        var types = GetMimeTypes();
        var ext = Path.GetExtension(path).ToLowerInvariant();
        return types[ext];
    }

    private Dictionary<string, string> GetMimeTypes()
    {
        return new Dictionary<string, string>
        {
            {".txt", "text/plain"},
            {".pdf", "application/pdf"},
            {".doc", "application/vnd.ms-word"},
            {".docx", "application/vnd.ms-word"},
            {".xls", "application/vnd.ms-excel"},
            {".png", "image/png"},
            {".jpg", "image/jpeg"},
            {".jpeg", "image/jpeg"},
            {".gif", "image/gif"},
            {".csv", "text/csv"}
        };
      }

My view component :

<form>
  <div class="form-group">
      <label> Code :  </label>
      @Html.DropDownList("TopCode", null, htmlAttributes: new { @class ="form-control" })
  </div>
  <script type="text/javascript">
      $(document).ready(function () {
        $('#download').click(function () {
              {
                var fName = $("#TopCode option:selected").val().toString();
                var _url = '@Url.Action("Download", "Profile")';
                $.ajax({
                    type: "POST",
                    url: _url,
                    xhrFields: {
                        responseType: 'blob'
                    },
                    data: {
                        filename: fName,
                    },
                });           
              }
           });
      });
  </script>
  <div class="form-group">
        <input id="download" type="button" value=" download "/>  
  </div>

</form>

when I clicked on download button, nothing happened. In tracing code, I don't find any problem. File name send to action correctly. I think It's a problem from ajax method. but I don't find it. Can someone help me?

Note: If file name was known , with this following code that replace with input tag, I could download the known file.

<a asp-action="Download" asp-controller="Profile" asp-route-filename="1.pdf"> download </a>
Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
NedaM
  • 87
  • 3
  • 10
  • 1
    You should do something in the "success" function – nicolascolman Jan 02 '21 at 11:20
  • @nicolascolman I guessed it. but I don't find any code that worked. – NedaM Jan 02 '21 at 11:23
  • 1
    Try with this example https://codepen.io/chrisdpratt/pen/RKxJNo. They key is in the createObjectURL method – nicolascolman Jan 02 '21 at 11:27
  • @nicolascolman I copied success function in my code. but it didn't work unfortunatly!! :( – NedaM Jan 02 '21 at 11:33
  • 1
    Why complicated, when it's easy. That's the web, just make your JS code access the url directly and the browser will handle the rest and offer you a download dialog. The browser recognizes if the header is set properly with `Content-Disposition: attachment; filename="filename.ext`. – Tseng Jan 02 '21 at 11:41
  • @Tseng I don’t understand your descreption . Could you describe it with an example, please? – NedaM Jan 02 '21 at 17:18
  • 1
    Just create a link: ``. Also, no need for `MemoryStream` here, waste of resources. Just stream it from the file system – Tseng Jan 02 '21 at 18:11
  • @Tseng Thanks for your help but I think you didn't read my problem :) . I can't define explicit filename. and this issue has caused using script and ajax for passing filename implicitly. – NedaM Jan 03 '21 at 03:51
  • No, you don't understand. Nothing prevents you from changing the href via javascript either. Plain old HTML , nothing else – Tseng Jan 03 '21 at 11:58
  • @NedaM really? It worked for me. I'll paste the complete JavaScript as an aswer. – nicolascolman Jan 03 '21 at 13:20
  • Hi @NedaM,The js also could work for me,maybe you need share more code.And what is your version of asp.net core?If you use asp.net core 2.x,you could follow the answer below:https://stackoverflow.com/a/59318687/11398810 – Rena Jan 04 '21 at 08:38

1 Answers1

1

As I mentioned in the comments, I only had to change the javascript code. It works in Chrome and Edge

<script type="text/javascript">
  $(document).ready(function () {
    $('#download').click(function () {
          {
            var fName = $("#TopCode option:selected").val().toString();
            var _url = '@Url.Action("Download", "Profile")';
            $.ajax({
                type: "POST",
                url: _url,
                xhrFields: {
                    responseType: 'blob'
                },
                data: {
                    filename: fName,
                },
                success: function (data) {
                    var a = document.createElement('a');
                    var url = window.URL.createObjectURL(data);
                    a.href = url;
                    a.download = 'myfile.pdf';
                    document.body.append(a);
                    a.click();
                    a.remove();
                    window.URL.revokeObjectURL(url);
                }
            });
          }
       });
  });
</script>
nicolascolman
  • 549
  • 4
  • 15