0

I used WebClient for uploading a file with few headers and it worked perfectly. But now I am creating a universal app using HttpClient. I don't understanding how to add file path to request header. Please see the following code:

public async void testUploadFile()
{
    string url = "http://localhost/webdav/";
    string filepath = @"C:\mydata\file-1.txt";
    string resource_name = Path.GetFileName(filepath);
    url += resource_name;
    HttpMultipartFormDataContent multipart = new HttpMultipartFormDataContent();
    multipart.Headers.Add("RequestId", "abc");
    multipart.Headers.Add("UserId", "apple");
    multipart.Headers.Add("SessionId", "ssdfsd22");
    Stream stream = new System.IO.MemoryStream();
    HttpStreamContent streamContent = new HttpStreamContent(stream.AsInputStream());
    multipart.Add(streamContent);
    httpClient = new HttpClient();

    HttpResponseMessage respMesg =await httpClient.PutAsync(new Uri(url), multipart);
    Debug.WriteLine(respMesg.Content);
}

Can anyone sort out this issue? Thank you in advance!

user3079834
  • 2,009
  • 2
  • 31
  • 63

2 Answers2

1

The following code works for one time upload:

public async void testFileUploadWebDAV()
{      
    string url = "http://localhost/webdav/";
    string userId = "xxx";
    string sessionId = "yyy";

    var filter = new HttpBaseProtocolFilter(); 
    filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
    filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain);

    var filePicker = new FileOpenPicker();
    filePicker.FileTypeFilter.Add("*");
    filePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
    StorageFile file = await filePicker.PickSingleFileAsync();
    url += file.Name;

    httpClient = new HttpClient(filter);
    msg = new HttpRequestMessage(new HttpMethod("PUT"), new Uri(url));

    httpClient.DefaultRequestHeaders.Add("RequestId", file.DisplayName);
    httpClient.DefaultRequestHeaders.Add("UserId", userId);
    httpClient.DefaultRequestHeaders.Add("SessionId", sessionId);
    httpClient.DefaultRequestHeaders.Add("ContentType", file.ContentType);

    Certificate cert = msg.TransportInformation.ServerCertificate;
    //-----------------ADD FILE CONTENT TO BODY-----------

    HttpStreamContent content = new HttpStreamContent(await file.OpenReadAsync());
    try
    {
        HttpResponseMessage httpResponseContent = await httpClient.PutAsync(new Uri(url), content);
        Debug.WriteLine(httpResponseContent.ToString());
        if (httpResponseContent.IsSuccessStatusCode)
        {                        
            msg.Dispose();                        
            httpClient.Dispose();
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
    }                    
}
user1991179
  • 573
  • 3
  • 8
  • 25
1

@Brajesh's answer was super helpful for me, but I needed a .NET Core solution. In particular, I found there to be some issues with encoding support in .NET Core, so I couldn't just pass an StreamContent into the httpClient.PutAsync method. Please see below for the .NET Core equivalent:

public static async void writeToWebDAV(string sourceFilename, Stream httpStream)
{
    //As described above, decoding must be forced as UTF8 default returns some strange results
    var content = Encoding.GetEncoding("iso-8859-1").GetString(readToEnd(httpStream));
    using (var httpClient = new HttpClient())
    {
        httpClient.DefaultRequestHeaders.Add("RequestId", sourceFilename);
        //Be sure user:pass is in Base64 encoding, can use this resource https://www.base64encode.org/
        httpClient.DefaultRequestHeaders.Add("Authorization", "Basic dXNlcjpwYXNzd29yZA==");
        StringContent c = new StringContent(content, Encoding.UTF8);
        try
        {
            HttpResponseMessage httpResponseContent = await httpClient.PutAsync(
                new Uri(Path.Combine(@"https://randomhost.com:5009/shareFolder", sourceFilename)), c);
            if (httpResponseContent.IsSuccessStatusCode)
                httpClient.Dispose();
            else
            {
                try
                {
                    //occasionally the server will respond with the WWW-Authenticate header in which case you need to re-PUT the file
                    //described here: https://stackoverflow.com/questions/32393846/webdav-return-401-how-to-authenticate
                    HttpResponseMessage httpResponseContent = await httpClient.PutAsync(
                        new Uri(Path.Combine(@"https://randomhost.com:5009/shareFolder", sourceFilename)), c);
                    if (httpResponseContent.IsSuccessStatusCode)
                        httpClient.Dispose();
                    else if (httpResponseContent.StatusCode.ToString() == "401")
                        Console.WriteLine("WebDAV Authentication Error...");
                }
                catch (Exception ex)
                { Console.WriteLine(ex.Message); }
            }
        }
        catch (Exception ex)
        { Console.WriteLine(ex.Message); }
    }
}

//Taken from StackOverflow: https://stackoverflow.com/questions/1080442/how-to-convert-an-stream-into-a-byte-in-c
public static byte[] readToEnd(Stream stream)
{
    long originalPosition = 0;

    if (stream.CanSeek)
    {
        originalPosition = stream.Position;
        stream.Position = 0;
    }
    try
    {
        byte[] readBuffer = new byte[4096];
        int totalBytesRead = 0;
        int bytesRead;

        while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
        {
            totalBytesRead += bytesRead;
            if (totalBytesRead == readBuffer.Length)
            {
                int nextByte = stream.ReadByte();
                if (nextByte != -1)
                {
                    byte[] temp = new byte[readBuffer.Length * 2];
                    Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                    Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                    readBuffer = temp;
                    totalBytesRead++;
                }
            }
        }
        byte[] buffer = readBuffer;
        if (readBuffer.Length != totalBytesRead)
        {
            buffer = new byte[totalBytesRead];
            Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
        }
        return buffer;
    }
    finally
    {
        if (stream.CanSeek)
            stream.Position = originalPosition;
    }
}
user1991179
  • 573
  • 3
  • 8
  • 25