简体   繁体   中英

Uploading a file using Windows.Web.Http from UWP app to a WebAPI web service

My Windows 10 UWP app is calling a WebAPI web service that I have created. I need to send a JPG file from the UWP app to the server so that the server can store it into another application.

I am using using Windows.Web.Http; as recommended for UWP and using Windows Authentication to connect to the server.

When I perform a POST using the following code, I get the IRandomAccessStream does not support the GetInputStreamAt method because it requires cloning error shown below.

I am able to POST HttpStringContent to the same web service and receive the responses without any issue.

The issue is when trying to send a file to the web service using HttpStreamContent .

public async void Upload_FileAsync(string WebServiceURL, string FilePathToUpload)
{

    //prepare HttpStreamContent
    IStorageFile storageFile = await StorageFile.GetFileFromPathAsync(FilePathToUpload);
    IBuffer buffer = await FileIO.ReadBufferAsync(storageFile);
    byte[] bytes = System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions.ToArray(buffer);
    Stream stream = new MemoryStream(bytes);
    Windows.Web.Http.HttpStreamContent streamContent = new Windows.Web.Http.HttpStreamContent(stream.AsInputStream());


    //send request
    var myFilter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
    myFilter.AllowUI = false;
    var client = new Windows.Web.Http.HttpClient(myFilter);
    Windows.Web.Http.HttpResponseMessage result = await client.PostAsync(new Uri(WebServiceURL), streamContent);
    string stringReadResult = await result.Content.ReadAsStringAsync();

}

Full Error:

{System.NotSupportedException: This IRandomAccessStream does not support the GetInputStreamAt method because it requires cloning and this stream does not support cloning. at System.IO.NetFxToWinRtStreamAdapter.ThrowCloningNotSuported(String methodName) at System.IO.NetFxToWinRtStreamAdapter.GetInputStreamAt(UInt64 position) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at }

Please help!

After you get the file and begin to create a HttpStreamContent instance, you can try to use the StorageFile.OpenAsync method to get an IRandomAccessStream object, then put it as the HttpStreamContent object constructor parameter.

The code will be like this, you can have a try.

public async void Upload_FileAsync(string WebServiceURL, string FilePathToUpload)
{

    //prepare HttpStreamContent
    IStorageFile storageFile = await StorageFile.GetFileFromPathAsync(FilePathToUpload);

    //Here is the code we changed
    IRandomAccessStream stream=await storageFile.OpenAsync(FileAccessMode.Read);
    Windows.Web.Http.HttpStreamContent streamContent = new Windows.Web.Http.HttpStreamContent(stream);

    //send request
    var myFilter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
    myFilter.AllowUI = false;
    var client = new Windows.Web.Http.HttpClient(myFilter);
    Windows.Web.Http.HttpResponseMessage result = await client.PostAsync(new Uri(WebServiceURL), streamContent);
    string stringReadResult = await result.Content.ReadAsStringAsync();
}

In Web API Controller

public IHostingEnvironment _environment;
public UploadFilesController(IHostingEnvironment environment) // Create Constructor 
{
    _environment = environment;
}

[HttpPost("UploadFiles")]
public Task<ActionResult<string>> UploadFiles([FromForm]List<IFormFile> allfiles)
{
    string filepath = "";
    foreach (var file in allfiles)
    {
        string extension = Path.GetExtension(file.FileName);
        var upload = Path.Combine(_environment.ContentRootPath, "FileFolderName");
        if (!Directory.Exists(upload))
        {
            Directory.CreateDirectory(upload);
        }
        string FileName = Guid.NewGuid() + extension;
        if (file.Length > 0)
        {
            using (var fileStream = new FileStream(Path.Combine(upload, FileName), FileMode.Create))
            {
                file.CopyTo(fileStream);
            }
        }
        filepath = Path.Combine("FileFolderName", FileName);
    }
    return Task.FromResult<ActionResult<string>>(filepath);
}

In yourpage.xaml.cs

using Windows.Storage;
using Windows.Storage.Pickers;
.....
StorageFile file;
......

private async void btnFileUpload_Click(object sender, RoutedEventArgs e) // Like Browse button 
{
    try
    {
        FileOpenPicker openPicker = new FileOpenPicker();
        openPicker.ViewMode = PickerViewMode.Thumbnail;
        openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
        openPicker.FileTypeFilter.Add(".pdf");
        file = await openPicker.PickSingleFileAsync();
        if (file != null)
        {
            //fetch file details
        }
    }
    catch (Exception ex)
    {

    }
}

//When upload file
var http = new HttpClient();
var formContent = new HttpMultipartFormDataContent();
var fileContent = new HttpStreamContent(await file.OpenReadAsync());
formContent.Add(fileContent, "allfiles", file.Name);
var response = await http.PostAsync(new Uri("Give API Path" + "UploadFiles", formContent);
string filepath = Convert.ToString(response.Content); //Give path in which file is uploaded

Hope this code helps you...

But remember formContent.Add(fileContent, "allfiles", file.Name); line is important and allfiles is that name of parameter to fetch files in web api method "public Task<ActionResult<string>> UploadFiles([FromForm]List<IFormFile> **allfiles**)"

Thanks!!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM