Sending Fileupload from HTTPClient to dotnet core Application - c#

i have a Server Application using dotnet core Controllers. There I have this Controller:
[HttpPost]
[RequestSizeLimit(100_000)]
public async Task<IActionResult> xxx([FromForm] string name, [FromForm] string description, [FromForm] bool isprivate, [FromForm] IFormFile icon)
{
...
}
When i send the request from my Frontend in the Browser, it works fine, generating this request:
Frame 103: 2148 bytes on wire (17184 bits), 2148 bytes captured (17184 bits) on interface \Device\NPF_Loopback, id 2
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 51141, Dst Port: 8001, Seq: 4701, Ack: 1792, Len: 2064
Hypertext Transfer Protocol
POST /api/xxx/xxxHTTP/1.1\r\n
Host: localhost:8001\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0\r\n
Accept: application/json, text/plain, */*\r\n
Accept-Language: de,en-US;q=0.7,en;q=0.3\r\n
Accept-Encoding: gzip, deflate\r\n
Content-Type: multipart/form-data; boundary=---------------------------20261806215495369501698203786\r\n
Content-Length: 1127\r\n
Origin: http://localhost:8001\r\n
DNT: 1\r\n
Connection: keep-alive\r\n
Referer: http://localhost:8001/xxx\r\n
[truncated]Cookie: .AspNetCore.Cookies=CfDJ8M_ELI8knopFkQ6zEqeCkgwDf43UGRqyyzwLWbKrkSuSRcmzqAPIcsi94bVzQFVWJB0NOGVRZVgzm4n7sf-0ox3SPK1ChgaqQuPRTogxdWzbJZPo1DCCi1TMI04RH4tmMj8rgv8EwDko5s1S2BNw0Owj8qL_-loCOz2VYU7wG3lVl5TIVavb46_nV6_Zr6MVdz
\r\n
[Full request URI: http://localhost:8001/api/xxx/xxx]
[HTTP request 6/6]
[Prev request in frame: 97]
[Response in frame: 107]
File Data: 1127 bytes
MIME Multipart Media Encapsulation, Type: multipart/form-data, Boundary: "---------------------------20261806215495369501698203786"
[Type: multipart/form-data]
First boundary: -----------------------------20261806215495369501698203786\r\n
Encapsulated multipart part:
Boundary: \r\n-----------------------------20261806215495369501698203786\r\n
Encapsulated multipart part:
Boundary: \r\n-----------------------------20261806215495369501698203786\r\n
Encapsulated multipart part:
Boundary: \r\n-----------------------------20261806215495369501698203786\r\n
Encapsulated multipart part: (image/png)
Last boundary: \r\n-----------------------------20261806215495369501698203786--\r\n
Now i also have a Client written in C# using the HTTPClient, and i can't get the fileupload working.
This is my code there right now:
public async Task<string?> Addxxx(string name, string description, bool isPrivate, byte[] ImageData, CancellationToken token)
{
var url = $"{Scheme}://{Address}:{Port}/api/xxx/xxx";
var Content = new MultipartFormDataContent();
var ImageContent = new ByteArrayContent(ImageData);
ImageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
Content.Add(ImageContent);
var request = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = new MultipartFormDataContent()
{
{
new FormUrlEncodedContent(new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("name" , name),
new KeyValuePair<string, string>("description" , description),
new KeyValuePair<string, string>("isprivate" , isPrivate.ToString()),
})
},
{Content }
}
};
request.Headers.Add("Accept", "multipart/form-data");
request.Headers.Add("User-Agent", UserAgent);
request.Headers.Add("Cookie", Cookies);
var response = await HttpClient.SendAsync(request, token);
if (!response.IsSuccessStatusCode)
return null;
...
}
However, this always gets a bad request.
This is the request generated:
Frame 16: 1523 bytes on wire (12184 bits), 1523 bytes captured (12184 bits) on interface \Device\NPF_Loopback, id 2
Null/Loopback
Internet Protocol Version 4, Src: 192.168.2.101, Dst: 192.168.2.101
Transmission Control Protocol, Src Port: 51121, Dst Port: 8001, Seq: 1394, Ack: 1020, Len: 1439
Hypertext Transfer Protocol
POST /api/xxx/xxxHTTP/1.1\r\n
Host: 192.168.2.101:8001\r\n
Accept: multipart/form-data\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36\r\n
[truncated]Cookie: .AspNetCore.Cookies=CfDJ8M_ELI8knopFkQ6zEqeCkgx2TK33iweuVbSNkdR_HNs5nC6EEy6zFxnuwpIovyH9WenSzaVCDgW3VWk0BJJ7cDnfdnQ5W_o98sJvaVtiVmPk3JB8e5bySGdcoRN6NwIl27mqLMl89Kt5hnsrq5Jps9Q3kJ1XSk5kpMciycb9AijtG9N_tqqqhRbV9EvbQc0CUU
Request-Id: |10c9eb89-46f0038fdc2e3b2d.\r\n
Content-Type: multipart/form-data; boundary="4265ae7c-56da-4811-b646-fc1123794472"\r\n
Content-Length: 576\r\n
\r\n
[Full request URI: http://192.168.2.101:8001/api/xxx/xxx]
[HTTP request 3/3]
[Prev request in frame: 10]
[Response in frame: 20]
File Data: 576 bytes
MIME Multipart Media Encapsulation, Type: multipart/form-data, Boundary: "4265ae7c-56da-4811-b646-fc1123794472"
[Type: multipart/form-data]
First boundary: --4265ae7c-56da-4811-b646-fc1123794472\r\n
Encapsulated multipart part: (application/x-www-form-urlencoded)
Boundary: \r\n--4265ae7c-56da-4811-b646-fc1123794472\r\n
Encapsulated multipart part: (multipart/form-data)
Last boundary: \r\n--4265ae7c-56da-4811-b646-fc1123794472--\r\n
I tried a lot and am a bit lost in how to Send the request from the Client...
Can someone point me in the right direction on how to send the image together with the other POST data?

Related

Multipart POST to the Joplin REST API using C# and Flurl

I am currently working on a console app to import data into Joplin for Windows 10, using C# and Flurl.
Joplin's API description can be found here.
I am trying to create a new resource in Joplin for a file on my system, so it can be attached to a Joplin note.
With CURL I can create the resource using command:
curl -F "data=#c:\\temp\\Test.pptx" -F "props={\"title\":\"my resource title\"}" http://localhost:41184/resources?token=MyToken
(note: it only works with "data=#c:\temp\Test.pptx", NOT with "data=c:\temp\Test.pptx")
When I try this with Flurl in c# I get a 400 response from Joplin, in the log I find:
Error: Resource cannot be created without a file
at Api.action_resources (C:\Program Files\Joplin\resources\app.asar\lib\services\rest\Api.js:351:37)
at Api.route (C:\Program Files\Joplin\resources\app.asar\lib\services\rest\Api.js:140:42)
at execRequest (C:\Program Files\Joplin\resources\app.asar\lib\ClipperServer.js:157:39)
at C:\Program Files\Joplin\resources\app.asar\lib\ClipperServer.js:185:8
at C:\Program Files\Joplin\resources\app.asar\node_modules\multiparty\index.js:136:9
at C:\Program Files\Joplin\resources\app.asar\node_modules\multiparty\index.js:115:9
at processTicksAndRejections (internal/process/task_queues.js:75:11)"
I have tried this so far:
try
{
var url = BaseUrl
.WithHeader("User_Agent", browserUserAgent)
.AppendPathSegment("resources")
.SetQueryParam("token", Token);
using (var fs = new FileStream("c:\\temp\\Test.pptx", FileMode.Open, FileAccess.Read))
{
var resource = url.PostMultipartAsync(mp => mp
.AddJson("props", new { title = "test title" })
.AddFile("data", fs, "Test.pptx", "application/octet-stream")
)
.ReceiveJson<JoplinResource>()
.Result;
}
}
and:
try
{
var url = BaseUrl
.WithHeader("User_Agent", browserUserAgent)
.AppendPathSegment("resources")
.SetQueryParam("token", Token);
var resource = url.PostMultipartAsync(mp => mp
.AddJson("props", new { title = "test title" })
.AddFile("data", "c:\\temp\\Test.pptx")
)
.ReceiveJson<JoplinResource>()
.Result;
}
I hooked up fiddler to see what is the difference between my application and CURL.
Curl:
POST http://127.0.0.1:41184/resources?token=MyToken HTTP/1.1
Host: 127.0.0.1:41184
User-Agent: curl/7.70.0
Accept: */*
Connection: Keep-Alive
Content-Length: 33648
Content-Type: multipart/form-data; boundary=------------------------91ab181cbb0247ba
--------------------------91ab181cbb0247ba
Content-Disposition: form-data; name="props"
{"title":"my resource title"}
--------------------------91ab181cbb0247ba
Content-Disposition: form-data; name="data"; filename="Test.pptx"
Content-Type: application/octet-stream
...
My Console app:
POST http://localhost:41184/resources?token=MyToken HTTP/1.1
User_Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36
Content-Type: multipart/form-data; boundary="f603841b-5c32-4e77-985a-69c2ffb6eed0"
Host: localhost:41184
Content-Length: 33612
Expect: 100-continue
Accept-Encoding: gzip, deflate
--f603841b-5c32-4e77-985a-69c2ffb6eed0
Content-Disposition: form-data; name=props
{"title":"My Resource"}
--f603841b-5c32-4e77-985a-69c2ffb6eed0
Content-Disposition: form-data; name=data; filename=Test.pptx; filename*=utf-8''Test.pptx
...
NOTE the differences:
props and data are in quotes when using CURL, not with FLURL
FLURL sends a second file name: filename*=utf-8''Test.pptx
How do I get this to work properly?
The issue was in the missing quotes for the "data" and "props":
try
{
var url = BaseUrl
.WithHeader("User_Agent", browserUserAgent)
.AppendPathSegment("resources")
.SetQueryParam("token", Token);
var resource = url.PostMultipartAsync(mp => mp
.AddJson("\"props\"", new { title = "My Resource" })
.AddFile("\"data\"", "c:\\temp\\Test.pptx")
)
.ReceiveJson<JoplinResource>()
.Result;
}
Raw request header is now:
POST http://localhost:41184/resources?token=MyToken HTTP/1.1
User_Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36
Content-Type: multipart/form-data; boundary="c6b2377a-1240-4ae3-872f-fa24b643d3e0"
Host: localhost:41184
Content-Length: 33616
Expect: 100-continue
Accept-Encoding: gzip, deflate
--c6b2377a-1240-4ae3-872f-fa24b643d3e0
Content-Disposition: form-data; name="props"
{"title":"My Resource"}
--c6b2377a-1240-4ae3-872f-fa24b643d3e0
Content-Disposition: form-data; name="data"; filename=Test.pptx; filename*=utf-8''Test.pptx
...
And the Joplin REST service creates a new resource...

how to post data to url using c#

i want send this data using post method in c#
POST https://lyncweb.contoso.com/ucwa/oauth/v1/applications/103...740/onlineMeetings/ myOnlineMeetings HTTP/1.1
Accept: application/json
Content-Type: application/json
Authorization: Bearer cwt=AAEB...buHc
X-Ms-Origin: http://localhost
X-Requested-With: XMLHttpRequest
Referer: https://lyncweb.contoso.com/Autodiscover/XFrame/XFrame.html
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; Trident/6.0;.NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; InfoPath.3)
Host: lyncweb.contoso.com
Content-Length: 185
DNT: 1
Connection: Keep-Alive
Cache-Control: no-cache
{
"attendanceAnnouncementsStatus":"Disabled",
"description":"hey guys let's do a musical!",
"subject":"holiday party",
"attendees": ["sip:Chris#contoso.com","sip:Alex#contoso.com"],
"leaders": []
}
please help me to write code in c# desktop application.
You can use Restsharp it is an lib that you can get from Nuget. very easy to use:
here is an example:
var client = new RestClient("http://example.com");
// client.Authenticator = new HttpBasicAuthenticator(username, password);
var request = new RestRequest("resource/{id}", Method.POST);
request.AddParameter("name", "value"); // adds to POST or URL querystring based on Method
request.AddUrlSegment("id", "123"); // replaces matching token in request.Resource
// easily add HTTP Headers
request.AddHeader("header", "value");
// add files to upload (works with compatible verbs)
request.AddFile(path);
// execute the request
IRestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
// or automatically deserialize result
// return content type is sniffed but can be explicitly set via RestClient.AddHandler();
RestResponse<Person> response2 = client.Execute<Person>(request);
var name = response2.Data.Name;
// easy async support
client.ExecuteAsync(request, response => {
Console.WriteLine(response.Content);
});
// async with deserialization
var asyncHandle = client.ExecuteAsync<Person>(request, response => {
Console.WriteLine(response.Data.Name);
});
// abort the request on demand
asyncHandle.Abort();

C# WebClient HTTP Basic Authentication Failing 401 with Correct Credentials

I'm trying to automate configuring a wireless router's SSID and Password via c# webclient. The router has no API that I know of. It's an unbranded chinese router. The web config seems to be the only option for configuration. It uses http-basic-authentication (you browse to the IP address of the router and get a generic dialog asking for username and password).
I've used Wireshark to get the headers and form fields that the http-post requests use when I manually update the SSID and Password (two separate forms). I then attempted to use webclient to emulate those post requests.
Here is a snippet of code that I am using to attempt to save a new SSID (NameValueCollection is defined elsewhere):
private const string FORM_SSID = "http://192.168.1.2/formWlanSetup.htm";
private const string REF_SSID = "http://192.168.1.2/formRedirect.htm?redirect-url=wlbasic.htm&wlan_id=0";
private NameValueCollection mFields = HttpUtility.ParseQueryString(string.Empty, Encoding.ASCII);
public string SaveConfigResponse()
{
try
{
using (WebClient wc = new WebClient())
{
wc.Headers[HttpRequestHeader.Accept] = "text/html, application/xhtml+xml, */*";
wc.Headers[HttpRequestHeader.Referer] = REF_SSID;
wc.Headers[HttpRequestHeader.AcceptLanguage] = "en-US";
wc.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko";
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
wc.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate";
wc.Headers[HttpRequestHeader.Host] = "192.168.1.2";
wc.Headers[HttpRequestHeader.Connection] = "Keep-Alive";
wc.Headers[HttpRequestHeader.ContentLength] = Encoding.ASCII.GetBytes(mFields.ToString()).Length.ToString();
wc.Headers[HttpRequestHeader.CacheControl] = "no-cache";
string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(config_user + ":" + config_pass));
wc.Headers[HttpRequestHeader.Authorization] = string.Format("Basic {0}", credentials);
//wc.Credentials = new NetworkCredential("admin", "admin");
return Encoding.ASCII.GetString(wc.UploadValues(FORM_SSID, "POST", mFields));
}
}
catch (Exception ex)
{
return ex.Message;
}
}
This results in an http-status-code-401 not authorized response. Is what I'm trying to do just impossible?
UPDATE
Here are the HTTP headers of both the browser post/response and the WebClient post/response. Again, I tried to match what I saw the browser posting as well as I could with my WebClient post.
Browser:
POST /formWlanSetup.htm HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Referer: http://192.168.1.2/formRedirect.htm?redirect-url=wlbasic.htm&wlan_id=0
Accept-Language: en-US
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: 192.168.1.2
Content-Length: 524
Connection: Keep-Alive
Cache-Control: no-cache
Authorization: Basic YWRtaW46YWRtaW4=
HTTP/1.1 302 Found
Location: wlbasic.htm
Content-Length: 183
Date: Thu, 23 Oct 2014 18:18:27 GMT
Server: eCos Embedded Web Server
Connection: close
Content-Type: text/html
Transfer-Encoding: chunked
Cache-Control: no-cache
WebClient:
POST /formWlanSetup.htm HTTP/1.1
Accept-Language: en-US
Accept-Encoding: gzip, deflate
Cache-Control: no-cache
Authorization: Basic YWRtaW46YWRtaW4=
Accept: text/html, application/xhtml+xml, */*
Content-Type: application/x-www-form-urlencoded
Referer: http://192.168.1.2/formRedirect.htm?redirect-url=wlbasic.htm&wlan_id=0
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: 192.168.1.2
Content-Length: 524
Connection: Keep-Alive
HTTP/1.1 401 Not Authorized
WWW-Authenticate: Basic realm="AP"
Date: Thu, 23 Oct 2014 18:18:41 GMT
Server: eCos Embedded Web Server
Connection: close
Content-Type: text/html
Transfer-Encoding: chunked
Cache-Control: no-cache
Again, that was all gleaned from Wireshark. I'm not very familiar with Wireshark, but I was able to get this far. If I knew how to properly extract the raw packet data and pastebin it, I would.
Important New Observations
The Wireshark captures of the post packets from both Browser and WebClient obviously differ in the order of the headers. I don't know how significant that might or might not be, though, as the data for each header is clearly the same.
One stark difference between the packets that I noticed is that Wireshark reports the Browser packet to be significantly larger than the WebClient packet. Looking at the itemized view, I couldn't find any obvious differences. I assume posting raw data for comparison would reveal a lot, but again, I don't really know how to do that.
I had a bewildering revelation. Despite the response clearly stating '(401) Unauthorized', the post is in fact being accepted by the router! Driving in to the router's web config after my WebClient post shows that the settings were accepted and saved.
That last one is a biggie. I find myself in a situation where I can get my config to save with a WebClient post, but I have to ignore a 401 response in order to do so. Obviously, this is far from ideal. So close, yet so far!
FINAL UPDATE (RESOLUTION)
I've solved the issue of failing basic authentication, though not with WebClient. I used the suggestion from #caesay and went with HttpWebRequest (together with WebResponse). My form posts result in redirects, so I had to allow for that.
This is essentially what I went with:
private bool ConfigureRouter()
{
bool passed = false;
string response = "";
HttpWebRequest WEBREQ = null;
WebResponse WEBRESP = null;
// Attempt to POST form to router that saves a new SSID.
try
{
var uri = new Uri(FORM_SSID); // Create URI from URL string.
WEBREQ = HttpWebRequest.Create(uri) as HttpWebRequest;
// If POST will result in redirects, you won't see an "OK"
// response if you don't allow those redirects
WEBREQ.AllowAutoRedirect = true;
// Basic authentication will first send the request without
// creds. This is protocol standard.
// When the server replies with 401, the HttpWebRequest will
// automatically send the request again with the creds when
// when PreAuthenticate is set.
WEBREQ.PreAuthenticate = true;
WEBREQ.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested;
// Mimic all headers known to satisfy the request
// as discovered with a tool like Wireshark or Fiddler
// when the form was submitted from a browser.
WEBREQ.Method = "POST";
WEBREQ.Accept = "text/html, application/xhtml+xml, */*";
WEBREQ.Headers.Add("Accept-Language", "en-US"); // No AcceptLanguage property built-in to HttpWebRequest
WEBREQ.UserAgent = USER_AGENT;
WEBREQ.Referer = REF_SSID;
WEBREQ.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
WEBREQ.KeepAlive = true;
WEBREQ.Headers.Add("Pragma", "no-cache"); // No Pragma property built-in to HttpWebRequest
// Use a cached credential so that the creds are properly
// submitted with subsequent redirect requests.
CredentialCache creds = new CredentialCache();
creds.Add(uri, "Basic", new NetworkCredential(config_user, config_pass));
WEBREQ.Credentials = creds;
// Submit the form.
using (Stream stream = WEBREQ.GetRequestStream())
{
SSID ssid = new SSID(ssid_scanned); // Gets predefined form fields with new SSID inserted (NameValueCollection PostData)
stream.Write(ssid.PostData, 0, ssid.PostData.Length);
}
// Get the response from the final redirect.
WEBRESP = WEBREQ.GetResponse();
response = ((HttpWebResponse)WEBRESP).StatusCode.ToString();
if (response == "OK")
{
StatusUpdate("STATUS: SSID save was successful.");
passed = true;
}
else
{
StatusUpdate("FAILED: SSID save was unsuccessful.");
passed = false;
}
WEBRESP.Close();
}
catch (Exception ex)
{
StatusUpdate("ERROR: " + ex.Message);
return false;
}
return passed;
}
Is what I'm trying to do just impossible?
No, its not impossible. I have had many headaches with web scraping like this over the years because some web servers are picky, and your router interface is likely a custom web server implementation that isnt as forgiving as apache or iis.
I would do a wireshark capture and get the raw packet data that chrome sends (w/ payload etc), and then do the same capture for your application. Make sure the packets are as similar as you can get them. If you still have issues, post the packet captures to pastebin or something so we can have a look.
EDIT::
Instead of using the limited WebClient API, try using some lower level items, I wonder if the following code will work for you:
var uri = new Uri("http://192.168.1.2/formWlanSetup.htm");
var cookies = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.CookieContainer = cookies;
request.ServicePoint.Expect100Continue = false;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko";
request.Referer = "http://192.168.1.2/formRedirect.htm?redirect-url=wlbasic.htm&wlan_id=0";
request.Credentials = new NetworkCredential(config_user, config_pass);
request.PreAuthenticate = true;
var response = request.GetResponse();
var reader = new StreamReader(response.GetResponseStream());
string htmlResponse = reader.ReadToEnd();

PostAsJsonAsync POST variables don't arrive at Flight PHP REST server

I have a Flight PHP REST server set up.
At 1 end point it expects POST data and based on one of the POST data it retrieves some data from the database and returns it as JSON.
When I use the Postman REST extension in Chrome I see the correct result. But when I do the call using my C# application the returned json is null because the $_POST seems empty.
This is my Flight index.php:
Flight::route('POST /getText', function(){
// Create a new report class:
$reportText = new ReportText;
$theText = $reportText->ParsePost($_POST);
if ($theText == null)
{
echo null;
}
else
{
echo json_encode($theText);
}
});
This is my ParsePost:
public function ParsePost($PostDictionary)
{
$textArray = null;
foreach ($PostDictionary as $key => $value)
{
if (!empty($value))
{
list($tmp, $id) = explode("_", $key);
$text = $this->geFooWithText($id);
$textArray[$key] = "bar";
}
}
return $textArray;
}
This is my C# part:
private static async Task RunAsyncPost(string requestUri)
{
using (var client = new HttpClient())
{
// Send HTTP requests
client.BaseAddress = new Uri("myUrl");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
try
{
// HTTP POST
var response = await client.PostAsJsonAsync(requestUri, new { question_8 = "foo", question_9 = "bar" });
response.EnsureSuccessStatusCode(); // Throw if not a success code.
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
if (string.IsNullOrEmpty(json))
{
throw new ArgumentNullException("json", #"Response from the server is null");
}
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
foreach (var kvp in dictionary)
{
Debug.WriteLine("Key: {0}, Value: {1}", kvp.Key, kvp.Value);
}
}
}
catch (HttpRequestException e)
{
// Handle exception.
Debug.WriteLine(e.ToString());
throw;
}
}
}
This is the response from Postman:
{
"question_8": "foo",
"question_9": "bar"
}
It seems I'm missing something in my call using C#.
[Update]
In this post (Unable to do a HTTP POST to a REST service passing json through C#) the same problem seems to appear.
Using Fiddler was suggested.
Using Postman and x-www-form-urlencoded:
POST http://myHost/api/getText HTTP/1.1
Host: myHost
Connection: keep-alive
Content-Length: 29
Cache-Control: no-cache
Origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: */*
Accept-Encoding: gzip,deflate
Accept-Language: nl-NL,nl;q=0.8,en-US;q=0.6,en;q=0.4
question_8=foo&question_9=bar
Using Postman and form-data:
POST http://myHost/api/getText HTTP/1.1
Host: myHost
Connection: keep-alive
Content-Length: 244
Cache-Control: no-cache
Origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryvb4wmaP4KooT6TFu
Accept: */*
Accept-Encoding: gzip,deflate
Accept-Language: nl-NL,nl;q=0.8,en-US;q=0.6,en;q=0.4
------WebKitFormBoundaryvb4wmaP4KooT6TFu
Content-Disposition: form-data; name="question_8"
foo
------WebKitFormBoundaryvb4wmaP4KooT6TFu
Content-Disposition: form-data; name="question_9"
bar
------WebKitFormBoundaryvb4wmaP4KooT6TFu--
Using my C#-application:
POST http://myHost/api/getText/ HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8
Host: myHost
Content-Length: 50
Expect: 100-continue
Connection: Keep-Alive
{"question_8":"foo","question_9":"bar"}
The C# application is sending it clearly in a different way.
I've found the problem.
Because I use client.PostAsJsonAsync() the POST data is send as json, as you can see in Fiddler.
PHP doesn't expects the POST data to be in json format.
To read that data I need to use $data = file_get_contents('php://input'); in my PHP file.
Now I have my keys and values and can I continue. It looks like PHP needs a $_JSON variable ;)

YUI Flash uploader not working: Unexpected end of MIME multipart stream

I'm using YUI 3 as an uploader control. I've created a WebAPI method that accepts POST transactions from YUI. When the HTML5 uploader is used, all works wonderfully. However, when I force it to Flash for testing, I'm encountering an error in my WebAPI method.
WebAPI
public async Task<HttpResponseMessage> Post()
{
if (!Request.Content.IsMimeMultipartContent())
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
await Request.Content.ReadAsMultipartAsync(provider);
int reviewId;
if (!Int32.TryParse(provider.FormData["ReviewId"], out reviewId))
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, new Exception("Invalid Review ID"));
foreach (MultipartFileData file in provider.FileData)
ProcessFile(reviewId, file);
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
}
}
I'm getting the following error when calling
await Request.Content.ReadAsMultipartAsync(provider):
Unexpected end of MIME multipart stream. MIME multipart message is not complete.
Again, the exact same WebAPI function works when the HTML5 uploader is sending the file so there must be some difference I'm not accounting for. For sake of completeness, here is the HTTP request:
POST http://localhost:11185/api/file HTTP/1.1
Host: localhost:11185
Connection: keep-alive
Content-Length: 7174
Origin: http://localhost:11185
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36
Content-Type: multipart/form-data; boundary=----------ae0ae0Ij5cH2GI3KM7Ef1Ef1ei4gL6
Accept: */*
Referer: http://localhost:11185/review/449913
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
------------ae0ae0Ij5cH2GI3KM7Ef1Ef1ei4gL6
Content-Disposition: form-data; name="Filename"
576619_334492516619692_690003897_n.jpg
------------ae0ae0Ij5cH2GI3KM7Ef1Ef1ei4gL6
Content-Disposition: form-data; name="ReviewID"
449913
------------ae0ae0Ij5cH2GI3KM7Ef1Ef1ei4gL6
Content-Disposition: form-data; name="Filedata"; filename="576619_334492516619692_690003897_n.jpg"
Content-Type: application/octet-stream
�����JFIF���������*���ICC_PROFILE���lcms��mntrRGB XYZ �����)�9acspAPPL����������������������������������-lcms�����������������������������������������������
desc�������^cprt��\���
wtpt��h���bkpt��|���rXYZ������gXYZ������bXYZ������rTRC������#gTRC������#bTRC������#desc�������c2����������������������������������������������������������������������������������text����FB��XYZ ��������������-XYZ ��������3���XYZ ������o���8����XYZ ������b��������XYZ ������$��������curv������������c�k
�?Q4!�)�2;�FQw]�kpz���|�i�}���0�����C�
%# , #&')*)-0-(0%()(���C
(((((((((((((((((((((((((((((((((((((((((((((((((((��������"�����������������������������������������������������������
�W��w��6����4d�b����h-�暖#�Z9#I
��\���]V��J�\}C��e)�vjC,�m2܈�c��e� $w)������9͑����K!%�LT��]G*N�s
��8�x"����!L�r�3��7*�����SR1���Ch���n�V+�g��Ņc
ֵ^YW�f*���D��H��G����D���Q
��d�Jrkfɩ,��א,�
c��"ķ<�c
��u1XX��6*d.Y�ê��j�)��9]i:Nz�7��ˢ�)H��®���&���U�/�ǭ4��d〬O��9`��ǽ-y(b�j�9�ll�b�Մt]��H��9��K]X���$X�W���H].tw1���4���D�dW����>�҃�s������-8�;�g7l.�����<�m���%=�,���(�D��V$94���*��������!"12 $3A#05�������^VEx�`uK�s��,Sc#�p��c٩[��<I��fxq��+nfe.:t���{v��(��o��SP�E�t,s̫p���'���6[�nLkn�R�m�A!�}�K!�����˺砚�knhm"^SY�t��+�xr��k���L�~1�ڡܭy�P���O���M�_�&��o����;Ν�ط���������#��E��v7�qUP8�c(XL�]���8Y��]��'��Nt��P���u"׵���j�8�8�S �rB��Q�s��,�->����w�XB�HJ��=YO{m1��"[ZKj/;�dD���ʛZ��W���6�,eΩ:�A��5�e`54"�dAZW'Ջ���_�6���+%xI�P��T7�.�k�G���=PRV��m�P㌪�����Wu#Q>�o���g�*��01�lc���]�g�0��Η���F�~8�ǽMWPt���O a�qߎע7�55�i�q�a����z9>�*�ɼG#��T~���pK���1���۔�l�3���G��T�k�u{���:��0�|��)ѹ��m����3j��5cdٍb���L�y8��e;�
�
�<gb;q�zy��Y׳����1ɌӤ�㓞��s#�=�[ɑ#�����5��
���dy;vŧ�d.5*�������t�f�_Y�ɦ�59*��O�N#�'�s}�������;����9�rЖ�V3U)/�ӌ��Σ`Z����şٛ�tD�.�:�� H��[�k5�
juW���W���`��������r���H�88�����Ex~�g�Y�{���g�Y�{��d��!�U���6׋_�Y��������������� !102���?��E�uG���=<�n����x���H�M1C�G�[f���:x�kL�p���rC1����"�����������! 1"Aq���?ەzZr�=9Q�d�)���ݲ-Q�1jŬ���>�V�MZ>
��%E��rJC�w�۪U+/��/K'��?L�?dz��e��m?[�.�v��1�%�umv�W����WT�����?���3��������!1A 2a"0Qq#3BR���r��#b������?��J�e6��D�:�X3�$�(�ݦ>�����,�gr��5�5c���^�������˘,���s���%ӚP�;�,��Z�%�# "8��ӥ��Ip)0?q^�hF�IFvW�fa�N�K�W������);(P�MhA_D��4���KM����\vO�o�ThW]۟�f��`��))��[L&i+�٘F�j���L�
�'�DW�O��3�nc�]���,�H�Z�t/l
-x�����dڍ�㢰���A+�w.�K�,h�uK�х��Ӕw�]�����ҵZ��>����.w�d��t�i���,��Ût�������^�xS2��S�.9B��Y:��:��/�ԥ��C�J��d��H]\�*6xg���S`o觎e˴C�P�>e?U
\OU0�P�����o5#����VwªRw��PlB�:YtVS�-Nα���j�ca�v�~�U����``�6R#
�.#���Vi�VZ��*84_t��}��\����GW�Y�vy�+)*�gr쬘��i��|��3Q�ػ�}U�T[��&7�=O���U8SA4m��� 3��vR��2��T.:�?���'�������!1AQaq������ ��������?!�'�� � ��?�HI��2]�x�ɈCK�[,Q��B�:��
�]���p��H!h���k\�y�$N'q��$/�"�B/z}����/Ȭ~�YHn�F�,3���7�E���#�4kcV�oB0�![t�kZ�L��jX|�0'nQc]�O��d��ouK8\��ov��ĵ���+'DMY���6���bL�
��N�'EСM���6�-�A,����d��
�x��%��A1R���ZX>�j�Ѐ$
��k��Xܛg�{')�x]�H��טm�D�i�#dlr3M�y7(�4FD�#�bI.���UV]�*(�_��)�<"ET�T
�ȽQ$m$� �n��5b�3$�,��
�J� �#r$�񵵐h�<>脢"�t3����M��Tp���-�AZ�i�r0��r��/�F*G%d�?���y
��"qP����ERHĜ���s%9e�-���r!�ن��bFwoDf�4k(����\��F?R(Z
�[Au�I��At�:d�^�ﭕ*�QX�rgP6m���m�"V)���:����dю%)P�l�O2Y$LT^<V���(#$D������ōi���j�#�v>U}X�
2CZ���\�u��C�������s�n�z�)��(�����
�ztoa�Dr��5�܉��Yz�ʏ�pw�+�-$ˤ����~�h��!2$��6z���F��H��Q��ֈ�s[���
Mo��;M�'�bu�w*jʲ�i�
p~�hV�6-�#��h��e2�c��?��"E�D0�e��)�R�aح�]�GP���NH�1W4$�M:rD����������mCn=H��pLZ?,sl8��l���Bl/��D��%���GO
r^-k^��V7n (�ܾτ�+�NR� ��������_��\�ԟcؾkY�U�i��2�N+�:D�E�r���y\��٪>�0:�,�����`d��A v��k�
aͦ���J��#��N��
�J�ӫ)�:iZC�6BD�B(�1}� L���,�*��$
�l9��n��}�;�ޏX��.ħ��v"\䌴>�w��Y�������8��D���[�����f�Q�փ-b^�� ��S%�4�24!�'��E���(�'��hR#��ЩC"x쵩�,v;�����������!1AQa���?����%��;ᯓ��b�d�{��3��k�o!~��v_���e���_dv�eZ��-Y���~X��՗����g�0�e�L�-
�,���O���X|_o�۩l�6`ɴx��X[��%?.ZX:]E��������������!1AQa����?�X�I}���/Sm��m�$�//����JxZ�
�Λn��#�u� �#�n�
&]��~�~'��#���0
;��<NG�����u&�.�^e�&����khK�sul���ߨ��ê?��u���~����_�'�=���?8����&�������!1AQaq��������������?)��α�W{���\-j*��`"yWA��VV+X�6�&P
!kY���l|Ī�5�f0��%�-�DY1�-C� ���)%(��
}��J�LH�8��M�����Ș�YJ�t*��-|CU,�ŏ�y�K�|��C2�-bcZ�T"Ջ�j���cR����<��l^���i��s���w�P�e��m�E������
1�w�zbY�2�3�_E�Ə�;�2�]Uj���
��YX�'nԿ
�]�k{����_� i�fH0P"�/ș�3(����;����l�N�uX� �9�:R�6�fӚ��/�����o�V�K��3m����v>��Q՗P��6���DQe�����������u1X�s#ԯ������7�exW�ry�1P�u,���1�����r��NE׶R8湇�ʸ�t,�>�G�F����AՔ�2�/�v!p��
�K���Z��/l
�\�!�>Y��\���,��� �m;/��b�w�m&����e�����J���~�eWR��!�O�T�E��ܾ~*�D���k����6�#�r���SD�НCB��tx�������q�#aw�$�q������w�������N�P�/�#����O�ʽ���`�f�Z�c��mҥ����X��-��ܲԙ;!��q�Ef�l:��*���Q�+W�q��=J�J��
Ų�]Tй-F$
#�7��0�tX�n
\
��-89F�a�F�~b\�q� �h���Ն�ß�ڳ*���߮�;��,�'lq���Qj��F�ۛ�2.n��-<���-�)���<�n�c��L���| ���G�r��4�������܉��L#7���%��c�6yX��q�lz�P�`V�Ы8{�c�Y�]J$`�+���U���*Ŋ����u�nMF*�vc�qg�B�(]��0��ڈڙ|\�;>������0gA��
�ӓ��_�Ԅ�V�}\I�#8�t:^‍���J<��{��
� m������IXn'���.*�/D*��S�6�ڕ�6WT�g�KQ���[!w�?�~#Q���e �"�'+��uW�*cP��u�/7���R���T+S�LTZuq���u0�h��:j�Q��Ө�jݮ(f�
�J��ZoR�A���!��t�AaH�BWF�
ۇ�L!��i�`P���
���gL}�^o�,���p?��)U��".&r��
�#R�\���ʫ����Q�K�
����cb�OL��(}����>"��"R�!T#:��Π!Wmc�4���C��4���g��,�$V��C/�h9��Z%��%+x^w�E�ñj��7&������?�K�� Yl���6e��(j-����R��%0e�l�5��$q
���G����3q|���n� ͹b�V�T<_�#������2�טƐ2�F6�6���Ĵ�U��������75jy>�)��
H9��$�A�������)�?0_�ª)<Jc���
��>L�D�g�t�n��w��+!e>H P��-`��(7��&6� �ĠU�����>2� �_��r�"�d�1e��B�`o�n�_-��[�M�s6�52�Cm��xc����z�Al=�zA;�&���D�^o������.�GȨ�b�Y��n�庈��`WXz���Xb�'#�� �2*�yQo1��>U)��&ᦥ�����m͑s[�x��HuY�<�G�j?P,0�����/�]qp\�q]#��Kh��ID7����pIEԠU{�s���#���^�N�0�xo=L]6(���W0�j�0�/.�s3TL�F��V�����X���4Qx1|�:.��[x~f~���v~�\���1��̯��M#�d{��eܞ<�UV�'���
��3�5,h������
------------ae0ae0Ij5cH2GI3KM7Ef1Ef1ei4gL6
Content-Disposition: form-data; name="Upload"
Submit Query
------------ae0ae0Ij5cH2GI3KM7Ef1Ef1ei4gL6--
Upgrading the ASP.NET WebAPI NuGet package to the latest version solved the problem.

Categories