Display upload progress in WPF app when uploading data to Azure through minimal web api

101 Views Asked by At

I am trying to make WPF application that uploads blobs to Azure Storage throught minimal web api with the help of HttpClient and displays upload progress at the same time. I have spent quite a while searching for solution, but haven't found anything that would work in this case. So far I have managed to do this. Here is my client code(WPF desktop app):

public void UploadFile(string path)
{
     var memoryStream = new MemoryStream(File.ReadAllBytes(path));
     var inputData = new StreamContent(memoryStream);

     var handler = new HttpClientHandler();
     var progressHandler = new ProgressMessageHandler(handler);
     progressHandler.HttpSendProgress += (o, args) =>
     {
     };

    var client = new HttpClient(progressHandler) { BaseAddress = new Uri("https://localhost:7088/") };
    var response = await client.PostAsync("weatherforecast", inputData);
    if (response.StatusCode == HttpStatusCode.OK)
    {
           
    }
}

In desktop app progressHandler reports only one time that is has uploaded all the data and it happens instantly when await body.CopyToAsync(memoryStream); in web api end point is hit (and the actual upload to Azure storage hasn't even started)

And then I have the server side code which receives Stream and then uploads it to the Azure Storage:

app.MapPost("/weatherforecast",async (Stream body) =>
{
    try
    {
        using (var memoryStream = new MemoryStream())
        {
           await body.CopyToAsync(memoryStream);

           var conStr = "myConString";
           var blobContainerClient = new BlobContainerClient(conStr, "containerName");
           BlobClient blobClient = blobContainerClient.GetBlobClient("MySample.txt");

           var progressHandler = new Progress<long>();
           progressHandler.ProgressChanged += (s, o) =>
           {
                //This reports progress as the file is uploaded
           };
           var options = new BlobUploadOptions
           {
               ProgressHandler = progressHandler
           };
           memoryStream.Position = 0;
           await blobClient.UploadAsync(memoryStream, options);
           return true;
        }
    }
    catch (Exception ex)
    {
        throw;
    }
});

For testing purposes I have a progressHandler here as well - this one reports the true upload progress which is the one I would like to see in my WPF desktop app. How do I pass this progress back to the caller? Is it even possible or I have to use some sort of third party library (for example SignalR) to achieve this? Please, don't be too harsh, these are my first steps in this area.

1

There are 1 best solutions below

1
On

Here is the way i'm able to display progress bar and make WPF application that uploads blobs to Azure Storage through minimal web api with the help of HttpClient and displays upload progress

1. Create a Minimal Web API: Created a Web API to handle blob uploads.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System.IO;
using System.Threading.Tasks;

[Route("api/blobs")]
[ApiController]
public class BlobController : ControllerBase
{
    private readonly IConfiguration _configuration;

    public BlobController(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    [HttpPost("upload")]
    public async Task<IActionResult> UploadBlob(IFormFile file)
    {
        if (file == null || file.Length == 0)
        {
            return BadRequest("No file uploaded.");
        }

        var storageAccount = CloudStorageAccount.Parse(_configuration.GetConnectionString("AzureStorage"));
        var blobClient = storageAccount.CreateCloudBlobClient();
        var container = blobClient.GetContainerReference("yourcontainername");

        if (await container.CreateIfNotExistsAsync())
        {
            await container.SetPermissionsAsync(new BlobContainerPermissions
            {
                PublicAccess = BlobContainerPublicAccessType.Blob
            });
        }

        var blobName = Guid.NewGuid().ToString(); // You can use a custom naming strategy.
        var blob = container.GetBlockBlobReference(blobName);

        using (var stream = file.OpenReadStream())
        {
            await blob.UploadFromStreamAsync(stream);
        }

        return Ok($"Blob uploaded with name: {blobName}");
    }
}

2. Configure Azure Storage Connection String: In the appsettings.json file of your Web API project, add your Azure Storage connection string:

{
  "ConnectionStrings": {
    "AzureStorage": "Your_Azure_Storage_Connection_String"
  }
}

3. Create the WPF Application: Created a WPF application that allows users to select a file and display the upload progress. You can use the HttpClient to upload the file to your Web API.

<Window x:Class="progress.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Blob Uploader" Height="250" Width="400">
    <Grid>
        <StackPanel Margin="10">
            <TextBlock Text="Select a file to upload:"/>
            <Button Content="Browse" Click="Browse_Click"/>
            <ProgressBar Name="progressBar" Height="20" Margin="0 10" IsIndeterminate="False" Value="0"/>
            <Button Content="Upload" Click="Upload_Click" IsEnabled="False"/>
        </StackPanel>
    </Grid>
</Window>

Now, in your code-behind (MainWindow.xaml.cs), you can enable and show the progress bar only when the upload process is initiated:

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace progress
{
    public partial class MainWindow : Window
    {
        private string selectedFilePath;
        private HttpClient httpClient = new HttpClient();
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Browse_Click(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new OpenFileDialog();
            if (openFileDialog.ShowDialog() == true)
            {
                selectedFilePath = openFileDialog.FileName;
            }
        }

        private async void Upload_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(selectedFilePath))
            {
                MessageBox.Show("Please select a file to upload.");
                return;
            }

            try
            {
                var fileContent = new StreamContent(System.IO.File.OpenRead(selectedFilePath));
                var formData = new MultipartFormDataContent();
                formData.Add(fileContent, "file", System.IO.Path.GetFileName(selectedFilePath));

                HttpResponseMessage response = await httpClient.PostAsync("http://yourapiurl/", formData);
                if (response.IsSuccessStatusCode)
                {
                    MessageBox.Show("File uploaded successfully.");
                }
                else
                {
                    MessageBox.Show("Upload failed.");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error: {ex.Message}");
            }
        }
    }
}

Result enter image description here

enter image description here enter image description here