Image upload from HTTP Client to C# Web Api - c#

I am trying to upload an image from (DHC by Restlet) to my C# API. In the future I want to call this API from an Android or iPhone App, but I figured that I need this part working before implementing it on any such device.
This C# code is put in my api:s ValuesController. The Controller I call by default. I have made sure (via breakpoints) that the below method is accessible and called properly.
public async Task<HttpResponseMessage> PostFormData()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
// Read the form data.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the file names.
foreach (MultipartFileData file in provider.FileData)
{
Trace.WriteLine(file.Headers.ContentDisposition.FileName);
Trace.WriteLine("Server file path: " + file.LocalFileName);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
.. However, I get the following error when trying to post a .png to my service:
System.IO.IOException was caught
HResult=-2146232800
Message=Unexpected end of MIME multipart stream. MIME multipart message is not complete.
Source=System.Net.Http.Formatting
StackTrace:
at System.Net.Http.Formatting.Parsers.MimeMultipartBodyPartParser.<ParseBuffer>d__0.MoveNext()
at System.Net.Http.HttpContentMultipartExtensions.MoveNextPart(MultipartAsyncContext context)
--- 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 Nutris.Webapi.Controllers.ValuesController.<PostFormData>d__12.MoveNext() in c:\Users\Simon\Documents\GitHub\Nutris\Nutris.Webapi\Controllers\ValuesController.cs:line 836
InnerException:
It occurs at the line:
await Request.Content.ReadAsMultipartAsync(provider);
What have I missed? It feels like I have forgotten to mention something about the mimetype for the above method.

Check the Inputs that are sending the data.
Make sure it has their basic attributes set like:
name:
type:
value: (I don't think this was is necessary.)
<input type="file" name="dataFile" value="Choose..." multiple/>
These are all necessary for the MIME to be considered complete and can be mapped correctly by your handler.
You should post your HTML side of code, to make sure it is the same issue.

Simon, try adding 'name' to your input control, you may be missing that.
<input type="file" id="fileInput" name="fileInput"/>
ASP.NET Web API, unexpected end of MIME multi-part stream when uploading from Flex FileReference

Related

CloudBlockBlob.DeleteAsync throws exception

I'm trying to delete a blob snapshot - I don't want to delete anything other than the snapshot for which I have the reference.
await snapshotBlob.DeleteAsync(DeleteSnapshotsOption.None,
acc,
new BlobRequestOptions(),
new OperationContext());
I've tried different DeleteSnapshotsOption but the exception tells me that only DeleteSnapshotsOption.None can be used when deleting a snapshot.
The AccessCondition (acc) has only the LeaseID set.
I don't have BlobRequestOptions or OperationContext preferences; I've also tried passing null for those two properties but it makes no difference.
The method call throws "The remote server returned an error: (400) Bad Request."
Stack trace:
Microsoft.WindowsAzure.Storage.StorageException at
Microsoft.WindowsAzure.Storage.Core.Executor.Executor.EndExecuteAsync[T](IAsyncResult
result) at
Microsoft.WindowsAzure.Storage.Blob.CloudBlob.EndDelete(IAsyncResult
asyncResult) at
Microsoft.WindowsAzure.Storage.Core.Util.AsyncExtensions.<>c__DisplayClass4.b__3(IAsyncResult
ar)
--- 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.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at StorageHooks.StorageBackup.d__0.MoveNext() in [line in my
code]
Can anyone explain what's wrong with the way I'm calling the method?
Also, in case it has an influence, I'm calling this method in an Azure Function. Furthermore, the code is copying existing blobs into another container, and the code works for creating a snapshot, creating the new blob, uploading to the other container, copying metadata, obtaining a lease... The only part which fails is deleting the snapshot.
I tried your code and traced the request/response through Fiddler. When I specified the lease id in the access condition, I got the 400 error. When I looked up the details, this is what the error message told me:
<?xml version="1.0" encoding="utf-8"?>
<Error>
<Code>InvalidQueryParameterValue</Code>
<Message>
Value for one of the query parameters specified in the request URI is invalid.
RequestId:cb8bcb1d-001e-004a-4811-991d8e000000
Time:2018-01-29T15:00:02.6030417Z
</Message>
<QueryParameterName>snapshot</QueryParameterName>
<QueryParameterValue>2018-01-29T14:55:27.3537780Z</QueryParameterValue>
<Reason>Leases are not allowed with snapshots.</Reason>
</Error>
Please try your request by removing the access condition from your request. When I did that, the request went just fine. So your code would be:
await snapshotBlob.DeleteAsync(DeleteSnapshotsOption.None)

Generate Embed Token For Create Issue

I have an issue with getting embed token. I've done all 5 steps which is described in this link (5 steps to push data into a dataset) and everything works perfectly: datasets are created, tables are created and filled in with data without any problems.
I have a task to embed a datasets (not reports) to web page.
I found this page (Power BI Embeded Sample) which shows how embed report/dataset/dashboard/tile will look like. And on this page there is an embed token.
I googled a little and found this page (Generate Embed Token Example) which describes the looks oh HTTP POST requests. I did the part for datasets. Here is my code example:
private static void generateEmbedToken()
{
// TokenCredentials Initializes a new instance of the
// Microsoft.Rest.TokenCredentials class with
// the given 'Bearer' token.
var credentials = new TokenCredentials(token);
// Initialize PowerBIClient with credentials
var powerBIclient = new Microsoft.PowerBI.Api.V2.PowerBIClient(credentials)
{
// BaseUri is the api endpoint, default is https://api.powerbi.com
BaseUri = new Uri("https://api.powerbi.com")
};
try
{
// Create body where accessLevel = View, datasetId = "" by default
var requestParameters = new GenerateTokenRequest(TokenAccessLevel.Create, datasetId, true);
// Generate EmbedToken This function sends the POST message
//with all parameters and returns the token
EmbedToken token = powerBIclient.Reports.GenerateTokenForCreate(requestParameters);
embedToken = token.Token;
}
catch (Exception exc)
{
Console.WriteLine(exc.ToString());
}
}
and I got next error:
Microsoft.Rest.HttpOperationException: Operation returned an invalid status code 'NotFound'
at Microsoft.PowerBI.Api.V2.Reports.<GenerateTokenForCreateWithHttpMessagesAsync>d__8.MoveNext()
--- 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 Microsoft.PowerBI.Api.V2.ReportsExtensions.<GenerateTokenForCreateAsync>d__7.MoveNext()
--- 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 Microsoft.PowerBI.Api.V2.ReportsExtensions.GenerateTokenForCreate(IReports operations, GenerateTokenRequest requestParameters)
at PushDataApp.Program.generateEmbedToken() in C:\Users\PC\Documents\Visual Studio 2017\Projects\PushDataApp\PushDataApp\Program.cs:line 388
here is line 388:
EmbedToken token = powerBIclient.Reports.GenerateTokenForCreate(requestParameters);
I don't know why it's happening.
I took this code from here (Generate Embed Token Example), but I did some changes for my purposes (because I need dataset and not report).
I'll appreciate any help.
I have come across a similar error when attempting to embed using Power BI. I recommend using a tool like Fiddler to intercept the communication between your application and Power BI and finding out the error code that is actually being returned.
The following article from Telerik shows how to intercept traffic using Fiddler: Capturing Traffic from .NET Services with Fiddler

C# REST - Send Request Body, Receive Response Body

I'm using the WebClient class. I've had some luck with the OpenReadTaskAsync method with a GET, but right now, I want to call a POST, or PUT REST method. I figured that I should use UploadStringTaskAsync. But, when I call this method on a working REST service, I get this error:
System.Net.WebException: An exception occurred during a WebClient request. ---> System.NotSupportedException: Specified method is not supported on this request.
at System.Net.Browser.BrowserHttpWebRequest.set_Method(String value)
at System.Net.WebClient.GetWebRequest(Uri address)
at System.Net.WebClient.UploadStringAsync(Uri address, String method, String data, Object userToken)
--- End of inner exception stack trace ---
at Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at CF.RESTClientDotNet.Silverlight.Sample.MainPage.d__3.MoveNext()
This is the code
var webClient = new WebClient();
var returnValue = await webClient.UploadStringTaskAsync(uri.AbsoluteUri, "POST", bodyString);
I ended up completely redesigning my library. There are samples here:
https://bitbucket.org/MelbourneDeveloper/restclient-.net/src/master/
NuGet: Install-Package RESTClient.NET

HttpRequestException when using HttpClient?

I was having a WebClient that was requesting an URL. I wanted to do the same thing within a UWP application, and I saw that I had to import Microsoft.Net.Http and use HttpClient.
So I replaced this(that was in a Class library):
WebClient client = new WebClient();
client.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2";
string content = client.DownloadString(url);
By this in a PCL library:
HttpClient client = new HttpClient();
string content = await client.GetStringAsync(url);
And now I got this exception:
System.Net.Http.HttpRequestException occurred
HResult=-2147012867
Message=An error occurred while sending the request.
Source=System.Net.Http
StackTrace:
at System.Net.Http.HttpClientHandler.<SendAsync>d__1.MoveNext()
--- 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 XXXX.YYYY.MHDJ.ZZZZ.<ParsePage>d__4.MoveNext()
InnerException:
ErrorCode=-2147012867
HResult=-2147012867
Message=Le texte associé à ce code d’erreur est introuvable.
Impossible d'établir une connexion avec le serveur
Source=""
StackTrace:
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.Http.HttpHandlerToFilter.<SendAsync>d__1.MoveNext()
--- 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.Net.Http.HttpClientHandler.<SendAsync>d__1.MoveNext()
InnerException:
I don't think the issue is the Headers, so what is?
The HRESULT code -2147012867 in hex is 0x80072EFD. The 0x8007 prefix means it's actually an HRESULT wrapper around a Win32 error code. The original Win32 error code is 0x2EFD.
The Win32 error code list tells us that values 0x2EE0 through 0x2F8F are ERROR_INTERNET_* error codes, which sounds like the right kind of error. After following the link to the Win32 ERROR_INTERNET_* error code listing, we can convert our error code 0x2EFD back to decimal (12029) and discover it is error ERROR_INTERNET_CANNOT_CONNECT:
The attempt to connect to the server failed.
Rather generic, and not much help.
I'd recommend trying the connection again, ensuring that your application has appropriate permissions and the device actually has a working Internet connection. If that doesn't work, try adding the UserAgent header back in; it's possible that the networking stack on your device insists on it.
Update: Tracking down the error code meaning was rather tedious, so I wrote an app to do it.
Experienced the 0x80072efd problem. Has cost me hours if not days to solve. The solution that worked for me was the following command from an admin command prompt:
netsh winhttp reset proxy
There are so many ways to do things, and I'm not suggesting that this is the best way, but this is how I construct my methods. This example is what I use to return a list of U.S. State objects that are provided in JSON format. One important note... this is in a Universal Windows class library, not a PCL... but I do not believe it uses anything that a PCL does not have access to.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using System.Threading.Tasks;
//IStateInfo is my model class interface
public async Task<IList<IStateInfo>> GetAllStatesAsync()
{
List<IStateInfo> states = new List<IStateInfo>();
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://YourBaseApiHere");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string url = "lookup/usstates";
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
//deserialize into client class Newtonsoft JSON used here
var lst = JsonConvert.DeserializeObject<List<StateInfo>>(json);
states.AddRange(lst);
}
else
{
//notify of failed web call here
}
}
}
catch (Exception e)
{
//notify of error
}
return states;
}

Windows.Web.Http.HttpClient#GetAsync throws an incomplete exception when invalid credentials are used with basic authentication

I am working on a Windows Runtime Component which makes API calls. Until earlier today I used the HttpClient and related models from System.Net but switched over to Windows.Web instead to leverage the WinRT streams.
Aside from changing the using statements, swapping HttpContent to IHttpContent and using the WindowsRuntimeExtensions to change my IInputStream to Stream for JSON.NET, I didn't have to do anything special. However suddenly 3 out of my 16 tests fail whereas previously everything worked.
All 3 (integration) tests validate that I receive an error response when logging in with invalid credentials. There are other tests that include logging in as well (but with valid credentials) and they work just fine. The given error message is of type AggregateException and has as message
System.AggregateException: One or more errors occurred. ---> System.Exception: Element not found.
A dialog cannot be displayed because the parent window handle has not been set.
The exception contains HRESULT values. The outerexception has value -2146233088 which corresponds to 0x80131500 while the innerexception has -2147023728 which corresponds to 0x80070490. Neither of those are a known error code on the MSDN page.
Following investigation:
0x80131500 corresponds to COR_E_EXCEPTION
0x80070490 corresponds to ERROR_NOT_FOUND
Stacktrace:
Result StackTrace:
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at xx.Models.Requests.GetRequest.<ExecuteRequestAsync>d__0.MoveNext() in c:\Users\jeroen\Github\Windows-app\xx\xx\Models\Requests\Request.cs:line 17
--- 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 xx.ApiDispatcher.<ExecuteAsync>d__0`2.MoveNext() in c:\Users\jeroen\Github\Windows-app\xx\xx\ApiDispatcher.cs:line 40
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
at xx.ApiDispatcher.Execute[TCallResult,TResponseObject](ApiCall`2 call) in c:\Users\jeroen\Github\Windows-app\xx\xx\ApiDispatcher.cs:line 22
Originally my question was worded somewhat differently because the actual problem seemed to be hidden. I have found out that the GET request by the HttpClient returns back to the caller instead of awaiting the result of the call (and executing the rest of the method).
In my project, executing the line var data = await myHttpClient.GetAsync(url); will return to the calling method with a non-constructed object and subsequent lines that come after the GetAsync() call are simply not executed.
Adding .ConfigureAwait(false) to stop it from going back did not make a difference.
The AggregateException is thrown when a user tries to login with invalid credentials. For some reason the HttpClient decides to throw an exception then without giving me a return value I could use. The problem here is that it does not tell me what kind of exception: catching COMException, TaskCanceledException, AggregateException and Exception only trigger the latter.
I have also found out that asynchronous integration tests do not work well with the multithreaded MSTest environment, so that explains several other failed tests that I had (but worked just fine individually)
I also, finally, have an example that demonstrates the problem (but I can't provide a webservice that takes basic auth)!
[TestMethod]
public void TestMethod3()
{
Assert.IsTrue(new Test().Do().AsTask().Result);
}
public sealed class Test
{
public IAsyncOperation<bool> Do()
{
return DoSomething().AsAsyncOperation();
}
private async Task<bool> DoSomething()
{
var client = new HttpClient();
var info = "jeroen.vannevel#something.com:nopass";
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes(info));
client.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("Basic", token);
var data = await client.GetAsync(new Uri("https://mytestdomain/v2/apikey?format=Json"));
return true;
}
}
Executing this code with a valid password will return true while an invalid password will throw an AggregateException.
Right now I am working around the problem by catching a general Exception around the call to GetAsync() but this is very rudimentary and I'd like to know why this incomplete exception is thrown in the first place.
After reconstructing your example and playing around, I figured out what happens.
var data = await client.GetAsync(new Uri("https://mytestdomain/v2/apikey?format=Json"));
The GetAsync method invokes the HTTP request with invalid credentials. What happens is that the returned request tries to look for a window where you can enter the correct credentials, but doesn't find one. Hence it throws an Element Not Found while searching for that window.
This can be fixed by creating a HttpBaseProtocolFilter and setting the AllowUI property to false and then passing it to the HttpClient:
private async Task<bool> DoSomething()
{
var httpBaseFilter = new HttpBaseProtocolFilter
{
AllowUI = false
};
var client = new HttpClient(httpBaseFilter);
var info = "jeroen.vannevel#something.com:nopass";
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes(info));
client.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("Basic", token);
var data = await client.GetAsync(new Uri("https://mytestdomain/v2/apikey?format=Json"));
return true;
}
Setting AllowUI on HttpBaseProtocolFilter to false will stop this error.
If however you do want a dialog box to display, allowing the user to enter credentials, then the web request needs to be started on the UI thread.
I think the problem is that the exception is actually thrown by your call to EnsureSuccessStatusCode.
Did you try adding HttpResponseMessage class EnsureSuccessStatusCode() method and check.
http://msdn.microsoft.com/en-us/library/system.net.http.httpresponsemessage.ensuresuccessstatuscode.aspx
After this line:
var data = await client.GetAsync(new Uri("https://mytestdomain/v2/apikey?format=Json"));
date.EnsureSuccessStatusCode();

Categories