Home > Enterprise >  C# - Download file from data URL
C# - Download file from data URL

Time:07-23

Summary

I'm wondering if there is a way to download the content of a data URL in C#, more specifically an image.

Background

Currently developing a Blazor Hybrid application which saves images from a canvas HTML element. The toDataUrl() method is invoked in JavaScript, then the url is retrieved by Blazor using JS interop. I've been having problems using this url to get the image, as HttpClient doesn't recognize it's format.

What I've tried

Using HttpClient

Throws Java.Net.MalformedURLException: unknown protocol

var imageUrl = await this.runtime.InvokeAsync<string>(SAVE);
byte[] image;

using HttpClient client = new()

image = await client.GetByteArrayAsync(imageUrl);
Downloading via JavaScript

Works on Windows, but not Android which is what I'm targeting. I've ensured that the proper permissions were requested.

const anchor = document.createElement('a')
const url = canvas.toDataURL()

anchor.download = 'painting.png'
anchor.href = url

anchor.click()
anchor.remove()

CodePudding user response:

Assuming you have the data url as a string,

First, extract the data using regex.

Then convert the base64 to bin and save the file.

//Input data url
string dataURL;

//Get Path and Filename
string filename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "image.png");

//Match Regex
var base64Data = Regex.Match(stringName, @"data:image/(?<type>. ?),(?<data>. )").Groups["data"].Value;
var binData = Convert.FromBase64String(base64Data);

//Write file. This will overwrite any existing file.
File.WriteAllBytes(filename, binData);

CodePudding user response:

The idea of downloading a whole file directly through a Blazor component makes me uncomfortable. Rather than using SignalR to transfer the file using interop, I prefer to make an old-style MVC controller, and submit the file as form data direct from js. From the controller's point of view, you are basically doing a file upload.

The nice thing about this method is you can send an image file from anywhere you want.

in Program.cs

// First in services builder:
builder.Services.AddMvc(options => options.EnableEndpointRouting = false);
// Then, near end after app.UseRouting():
app.UseMvcWithDefaultRoute();

The following is a working code sample for uploading a converted .mp3 file. I don't have the time to test a working model for your particular data, so you can't copy and paste, but the point is that you send the data as a file.

Uploader.js

async function UploadAudio(TextClipID, AudioID) {
    let filename = AudioID   ".mp3";
    let fd = new FormData();
    fd.append("file", mp3Blob[TextClipID], filename);
    var postresponse = await fetch('api/SaveAudio/Save/', {
        method: 'POST',
        body: fd
    });

    if (postresponse.ok) {
        // Do happy stuff, like calling a .NET method with the new path for your <img> source.
    }

    else return false;
}

Then add a new Controllers folder in your project for this and other MVC controllers you might want to use. Obviously, since mine is serving as an audio upload controller, you'd want to make / find a controller that handles image uploads:

/Controllers/SaveAudio.cs

public class SaveAudio : Controller
    {
        IWebHostEnvironment _hostingEnvironment;

        public SaveAudio(IWebHostEnvironment hostingEnvironment)
        {
            _hostingEnvironment = hostingEnvironment;

        }

        [Route("api/[controller]/Save")]
        [HttpPost]
        public async Task<IActionResult> Save(IFormFile file)
        {
            if (file.ContentType != "audio/mp3")
            {
                return BadRequest("Wrong file type");
            }
            var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "files", "audio", "Reading");

            var filePath = Path.Combine(uploads, file.FileName );
            using (var fileStream = new FileStream(filePath, FileMode.Create))
            {
                try
                {
                    await file.CopyToAsync(fileStream);
                    return Ok("File uploaded successfully at: "   filePath);
                }
                catch
                {
                    return BadRequest("Wrong file type");
                }
            }
            
        }
    }
  •  Tags:  
  • c#
  • Related