My issue is that my c# api controller is kicking back theFormData Post request when I check for multi-part data here: IsMimeMultipartContent(), which then throws the message back to the UI:
415 (Unsupported Media Type)
[HttpPost]
[Route("MediaUpload")]
public async Task<HttpResponseMessage> MediaUpload([FromUri]string sessionId, [FromUri]string patientId)
{
if (!Request.Content.IsMimeMultipartContent())
{ // *** ALWAYS THROWS ERROR ***
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
//access form data
var provider = await Request.Content.ReadAsMultipartAsync(new InMemoryMultipartFormDataStreamProvider());
NameValueCollection formData = provider.FormData;
//... additional code omitted
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("UploadPath", fullPath);
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
My front end payload looks like this:
REQUEST HEADERS
POST /api/import/MediaUpload?sessionID=c83f9589-742e-40e3-8cf5-7ffff141c3d7&patientId=5981 HTTP/1.1
Host: localhost:56703
Connection: keep-alive
Content-Length: 6545
Accept: application/json, text/plain, */*
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Content-Type: multipart/form-data
Referer: http://localhost:4200/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
REQUEST PAYLOAD
------WebKitFormBoundaryVrKSHPqdT9c6JkKv
Content-Disposition: form-data; name="enctype"
multipart/form-data
------WebKitFormBoundaryVrKSHPqdT9c6JkKv
Content-Disposition: form-data; name="MediaInfo"
[{"PatientID":5981,"PatientLastName":"Hobo","PatientFirstName":"John","DeviceID":"123","InstanceID":89,"PatientDOB":"1/3/1970","FileName":"image2.jpg","FileSize":5880,"ExamDate":"5/30/2018","PatientID":66665981,"SessionID":"sessionID=9999141c3d7"}]
------WebKitFormBoundaryVrKSHPqdT9c6JkKv
Content-Disposition: form-data; name="files[]"; filename="image2.jpg"
Content-Type: image/jpeg
ÿØÿàJFIFÿÛC
------WebKitFormBoundaryVrKSHPqdT9c6JkKv--
My front end is sending in FormData, generated in the following TypeScript method, then calling the importService further below:
save() {
let params = { patientID: ''};
let exDate = new Date(this.defaultDate).toLocaleDateString();
// Populate MediaInfo object
let minfo = this.SetMediaArray();
params.pID = minfo[0].PID;
const formData = new FormData();
formData.set("enctype", "multipart/form-data" ); // doesn't make a difference..
formData.append("MedInfo", JSON.stringify(minfo));
for(var i=0; i<this.importImages.length; i++){
// append images to the files[] array, then send formData object to impService
formData.append("files[]", this.dataURItoBlob(this.importImages[i].TnUrl), this.importImages[i].name);
}
let endpoint = this.selectedObj.Url;
this.importService.saveImportObjects(formData, params, endpoint).subscribe(
data=> {
console.log(data);
},
err => {
console.log(err);
}
);
}
So basically I would like to know exactly what http option I'm missing for this to work.
thank you.
I removed the multipart/boundary header attribute, and let the browser take care of it for you. The upload worked.
Related
I was trying to upload Multipart/form-data on Android using Okhttp, but it does not work.
The request header is
POST /api/texttospeech/v3.0-beta1//datasets/upload HTTP/1.1
Host: koreacentral.customvoice.api.speech.microsoft.com
Connection: keep-alive
Content-Length: 201455
Accept: application/json, text/plain, /
Correlation-Id: 290c5850-f621-11ea-ac4a-9dac0e19cc7b
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36 Edg/85.0.564.51
Ocp-Apim-Subscription-Key: 38fae10960fc477ba614c6dfe64613ba
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryZAaHsREIpzJ9sBHS
Origin: https://speech.microsoft.com
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Accept-Encoding: gzip, deflate, br
Accept-Language: ko,en;q=0.9,en-US;q=0.8
and the multipart/form-data is
------WebKitFormBoundaryZAaHsREIpzJ9sBHS
Content-Disposition: form-data; name="projectId"
1a685f5d-400b-4801-8adb-9d359cad27cb
------WebKitFormBoundaryZAaHsREIpzJ9sBHS
Content-Disposition: form-data; name="name"
16151
------WebKitFormBoundaryZAaHsREIpzJ9sBHS
Content-Disposition: form-data; name="description"
51561
------WebKitFormBoundaryZAaHsREIpzJ9sBHS
Content-Disposition: form-data; name="dataImportKind"
CustomVoice
------WebKitFormBoundaryZAaHsREIpzJ9sBHS
Content-Disposition: form-data; name="locale"
en-US
------WebKitFormBoundaryZAaHsREIpzJ9sBHS
Content-Disposition: form-data; name="properties"
{"Gender":"Male","IsMixLingual":"false","PortalAPIVersion":"3"}
------WebKitFormBoundaryZAaHsREIpzJ9sBHS
Content-Disposition: form-data; name="audiodata"; filename="1.zip"
Content-Type: application/x-zip-compressed
------WebKitFormBoundaryZAaHsREIpzJ9sBHS
Content-Disposition: form-data; name="transcriptions"; filename="transcript.txt"
Content-Type: text/plain
------WebKitFormBoundaryZAaHsREIpzJ9sBHS--
The code I created is something like this.
String boundary = "----WebKitFormBoundary" + result; //result is the random digits
String Url = String.format("https://%s.customvoice.api.speech.microsoft.com/api/texttospeech/v3.0-beta1//datasets/upload", region);
String audioPath = getFilesDir().getAbsolutePath()+"/audios.zip";
String scriptPath = getFilesDir().getAbsolutePath()+"/script.txt";
System.out.println("properties to String"+ properties.toString());
File audioFile = new File(audioPath);
File scriptFile = new File(scriptPath);
//Create request body (params or json)
System.out.println("audiopath is " + audioPath);
System.out.println("scriptpath is "+ scriptPath);
MultipartBody formBody = new MultipartBody.Builder(boundary)
.setType(MultipartBody.FORM)
.addFormDataPart("projectId", projectId)
.addFormDataPart("name", defaultVal)
.addFormDataPart("description", defaultVal)
.addFormDataPart("dataImportKind", "CustomVoice")
.addFormDataPart("locale", "en-US")
.addFormDataPart("properties", properties.toString())
.addFormDataPart("audiodata", "audios.zip", RequestBody.create(MediaType.parse("application/x-zip-compressed"), audioFile))
.addFormDataPart("transcriptions", "script.txt", RequestBody.create(MediaType.parse("text/plain"), scriptFile))
.build();
System.out.println(formBody);
Request request = new Request.Builder()
.header("Ocp-Apim-Subscription-Key", subKey)
.addHeader("Ocp-Apim-Subscription-Key", subKey)
.addHeader("Content-Type", formBody.contentType().toString())
.post(formBody)
.url(Url)
.build();
System.out.println("Data upload request : "+ request);
System.out.println("Data upload request : "+ request.body());
System.out.println("Data upload request : "+ request.body().toString());
//Response response = client.newCall(request).execute();
//System.out.println("data upload response "+response.body().string());
//response.close();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException {
System.out.println("Response "+response);
}
});
return null;
}
The error is
Response{protocol=http/1.1, code=500, message=Internal Server Error, url=https://koreacentral.customvoice.api.speech.microsoft.com/api/texttospeech/v3.0-beta1//datasets/upload}
The Internal Server Error seems to be wrong, since it works if I send the request through Python, using
from requests_toolbelt.multipart.encoder import MultipartEncoder
Code 500 means the server receives your request but fail to complete it.As the server performs well while using python according to your description, I guess that you got something wrong in your HTTP-Header or multipart/form-data.But it cannot be find out yet by the only info.I suggest that you should compare the data you send through okhttp and python to find out the difference.
i am working on an ESP32 project. one of my goals is to communicate with the ESP32 from a website using javascript fetch or XMLHttpRequest().
the ESP32 is connected to my local network and i am using the esp32_https_server library. it uses a self-signed certificate which the browser indicates as valid (but issues a warning, "Connection not protected" due to the self-signed certificate). the website has a CA certificate and is secure.
in testing, the esp32 is conected via USB to my computer, idealy i would like it to stand alone.
the problem i am experiencing is that i cannot seem to connect to the esp32. i keep getting status code 499 errors.
my questions are:
1) how do i successfully connect to the esp32 server from a secure website to get data frome the esp32?
2) how do i do this when the esp32 is not connected to my pc via the usb cable?
please see more info regarding the esp32 set up and responses below.
here's the esp32 code:
ResourceNode *nodeRoot = new ResourceNode("/", "GET", [](HTTPRequest *req, HTTPResponse *res) {
ResourceParameters *params = req->getParams();
std::string action = params->getRequestParameter("action");
String aksie = action.c_str();
Serial.println("Aksie: " + aksie);
if (aksie != "upload_data" && aksie != "upload_current_temp")
{
// this should be home page displayed
// Set the response status
res->setStatusCode(200);
res->setStatusText("success");
res->println("Secure Hello World!!!");
}
else
{
// either uploads..
processParams(aksie, res);
}
});
secureServer->registerNode(nodeRoot);
and here's the code that processes the "upload_current_temp" request:
if (action == "upload_current_temp")
{
// get random temperature
int currentTemp = random(0, 9);
String temp = String(currentTemp);
Serial.println("upload current temperature");
Serial.println("uploadCurrentTemp: " + temp);
std::string tem = temp.c_str();
// Set the response status
res->setStatusCode(200);
res->setStatusText("success current temperature");
StaticJsonDocument<200> doc;
doc["temperature"] = temp;
// Produce a minified JSON document
String output;
serializeJson(doc, output);
Serial.println("curent temp json output: " + output);
deserializeJson(doc, output);
// Set the content type of the response
res->setHeader("Content-Type", "application/json");
res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
// As HTTPResponse implements the Print interface, this works fine. Just remember
// to use *, as we only have a pointer to the HTTPResponse here:
serializeJson(doc, *res);
}
and also in setUp() i have this line:
secureServer->setDefaultHeader("Access-Control-Allow-Origin", "*"); //replace * with actual address
when using:
const xhr = new XMLHttpRequest();
const url = 'https://192.168.0.102/?action=upload_current_temp';
xhr.open('GET', url);
xhr.responseType = 'text';
xhr.onload = function () {
const data = xhr.response;
console.log(data);
if (this.readyState == 4 && this.status == 200) {
var obj = JSON.parse(this.responseText);
console.log("getCurTemp(), responseText: " + JSON.stringify(this.responseText, null, 2));
currentTemperature = obj.temperature;
console.log("current temperature: " + currentTemperature);
document.getElementById('currentTemp').innerHTML = currentTemperature;
}
};
xhr.send();
i get these errors (in opera):
499 (Request has been forbidden by antivirus)
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
and in chrome:
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
with these headers (opera):
Request URL: https://192.168.0.102/?action=upload_current_temp
Request Method: GET
Status Code: 499 Request has been forbidden by antivirus
Remote Address: 192.168.0.102:443
Referrer Policy: no-referrer-when-downgrade
Cache-Control: no-store, no-cache, must-revalidate, max-age=0
Connection: close
Content-Length: 52266
Content-Type: text/html; charset=utf-8
Expires: Mon, 04 Dec 1999 21:29:02 GMT
Pragma: no-cache
Accept: /
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: 192.168.0.102
Origin: https://istimuli.co.uk
Referer: https://istimuli.co.uk/?code=66b72f8e-400c-4adb-ad42-f4efec391d06
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36 OPR/67.0.3575.79
action: upload_current_temp
and when using :
var url = "https://192.168.0.102/?action=upload_current_temp";
var request = new Request(url, {
method: 'GET',
mode: 'cors', // no-cors, *cors, same-origin
headers: {
'Content-Type': 'application/json'
}
});
fetch(request).then(function (response) {
// Convert to JSON
return response.json();
}).then(function (data) {
console.log("temp: " + JSON.stringify(data));
return data;
}).catch(function (error) {
console.log('Request failed', error)
return 000;
});
i get these errors in opera:
499 (Request has been forbidden by antivirus)
has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
and in chrome:
has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
and these are the headers (opera):
1 requests
51.3 KB transferred
51.0 KB resources
Request URL: https://192.168.0.102/?action=upload_current_temp
Request Method: OPTIONS
Status Code: 499 Request has been forbidden by antivirus
Remote Address: 192.168.0.102:443
Referrer Policy: no-referrer-when-downgrade
Cache-Control: no-store, no-cache, must-revalidate, max-age=0
Connection: close
Content-Length: 52266
Content-Type: text/html; charset=utf-8
Expires: Mon, 04 Dec 1999 21:29:02 GMT
Pragma: no-cache
Accept: /
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: GET
Connection: keep-alive
Host: 192.168.0.102
Origin: https://istimuli.co.uk
Referer: https://istimuli.co.uk/?code=66b72f8e-400c-4adb-ad42-f4efec391d06
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36 OPR/67.0.3575.79
action: upload_current_temp
I have a Web Api project with this route config
var config = GlobalConfiguration.Configuration;
config.Routes.MapHttpRoute(
"DefaultApiRoute",
"api/v1/{controller}/{action}");
I have two post method
[HttpPost]
public IHttpActionResult RetrieveTestNoParam()
{
return new JsonResult<string>("This is a test", new JsonSerializerSettings(), Encoding.UTF8, this);
}
[HttpPost]
public IHttpActionResult RetrieveTest(string input)
{
return new JsonResult<string>(input, new JsonSerializerSettings(), Encoding.UTF8, this);
}
The first one is working but the second one gives this respone
{
"Message": "No HTTP resource was found that matches the request URI 'http://test.dev.local/api/v1/NewsApi/RetrieveTest'.",
"MessageDetail": "No action was found on the controller 'NewsApiController' that matches the request."
}
This is what I see in fiddler
POST http://test.dev.local/api/v1/NewsApi/RetrieveTest HTTP/1.1
Host: test.dev.local
Connection: keep-alive
Content-Length: 261
Cache-Control: no-cache
Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
Content-Type: application/javascript
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36
Postman-Token: c2ba631b-4bfd-9379-bf40-0ca1a6a8a3bc
Accept: */*
DNT: 1
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,nl;q=0.6
Cookie: ASP.NET_SessionId=4kgfwd2u3pwusfdvdsrkt2vt; SC_ANALYTICS_GLOBAL_COOKIE=ddd9185a3e8940c9823e81b7d38cdf20|False; sc_expview=0
------WebKitFormBoundaryxdYhzJ7A8WnI8qaa
Content-Disposition: form-data; name="input"
Dit is de input
------WebKitFormBoundaryxdYhzJ7A8WnI8qaa
Content-Disposition: form-data; name="czczcsdcsdf"
sdfsfsdfsdff
------WebKitFormBoundaryxdYhzJ7A8WnI8qaa--
Any ideas?
Other questions I have about Web Api:
Can a controller contain multiple get or post methods?
Do I need the actionname attribute and what does this attribute do?
Regards
Danny
trying to send a Fiddler Post request to my C# API as follows (this is my dev environment using VS2012). However, my request object is null in C#. In the parsed tab of the composer tab. My post URL: http://localhost:33218/api/drm
User-Agent: Fiddler/4.4.9.2 (.NET 4.0.30319.34209; WinNT 6.1.7601 SP1; en-US; 4xAMD64)
Pragma: no-cache
Accept-Language: en-US
Host: localhost:33218
Accept-Encoding: gzip, deflate
Connection: Close
Content-Length: 80
Request Body:
&sid=f7f026d60bb8b51&riskMeasureName=RMTest
And here's the C# API method:
// POST api/drm
public HttpResponseMessage Post([FromBody]JObject drmObject)
{
string sid = drmObject.GetValue("sid").ToString();
string riskMeasCategory = drmObject.GetValue("riskMeasureName").ToString();
string response = DynAggrClientAPI.insertDRMCategory(sid, riskMeasCategory);
var httpResp = Request.CreateResponse(HttpStatusCode.OK);
httpResp.Content = new StringContent(response, Encoding.UTF8, "application/json");
return httpResp;
}
I can debug in my C# Post() method, but the drmObject is null.
Your advice is appreciated.
You're not sending a content-type, so MVC has no way to tell how to interpret the data.
Your data seems to resemble a form POST, so add the header:
Content-Type: application/x-www-form-urlencoded
I'm trying to update data using WebApi PUT method. My code working fine before, but suddenly I start to get this error.
"Message":"The request contains an entity body but no Content-Type header. The inferred media type 'application/octet-stream' is not supported for this resource.","ExceptionMessage":"No MediaTypeFormatter is available to read an object of type 'xEmployee' from content with media type 'application/octet-stream'.","ExceptionType":"System.Net.Http.UnsupportedMediaTypeException".
This is headers:
Response Header.
HTTP/1.1 415 Unsupported Media Type
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.5
Set-Cookie: Role=D65520F37D105E39C1A92C15CD482E378F32A769592AC7D8305285A5B9B90362F7F2F13F14E6DC220E44D26940B06B52E7460EF13184F245805AF9523D1072464F4BD06AFB4F8AEB8B7D8BF607A8922C6041A3A4C636BF3B26388E606A94FE43; expires=Tue, 07-Oct-2014 09:49:56 GMT; path=/
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 07 Oct 2014 09:19:56 GMT
Content-Length: 809
Request Header:
PUT /api/xemployees/2110481232 HTTP/1.1
Host: guideonline.ilvestour.office
Connection: keep-alive
Content-Length: 229
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://guideonline.ilvestour.office
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
Content-Type: application/json; charset=UTF-8"
Referer: http://guideonline.ilvestour.office/account
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: .ASPXAUTH=215C424A0A023F5B42775B7A73B08FEC8CB36E7200FBA430EADF2F300A84500571F8B5EE980C3EF2913FE160978973CDBC50BDD216E16FC342EF0B566D0944ECFD901DF471DEF9F6E5D272B52F2450CC0A1FB96BCC6B3B6E7A7C07343D4DFBD66; Role=DE678EE89D7089B8CD74B202E00C53CA9AE9E4C40B506C5C4EEF56E7962F38ED86F6BFD34E5FD3A6DD6ECCCF61AF768CAB0C1D7C5F15A8638F9454B24DF3208F021EB638235420574C6420CA5A19F0B6BD07BAC303FF79612D6C1AF246563A7
Request Payloadview source
{"Kod":2110481232, "Сотрудник": "Lena", "Telephon": "088-6734227", "Password":"rimosa57", "email":"samoylova-elena#mail.ru", "CrWho":"OMEGA.Administrator", "CrWhen":"2014-10-07T09:20:05.735Z"}
Nothing special in Controller code:
[Authorize(Roles = "Admin, User")]
public async Task<IHttpActionResult> PutxEmployee(int id, xEmployee xEmployee)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != xEmployee.Kod)
{
return BadRequest();
}
try
{
var user = db.xEmployee.Find(id);
user.Сотрудник = xEmployee.Сотрудник;
user.Telephon = xEmployee.Telephon;
user.Password = xEmployee.Password;
user.email = xEmployee.email;
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!xEmployeeExists(id))
{
return NotFound();
}
else
{
throw;
}
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
var path = "C:/error.txt";
using (StreamWriter sw = File.CreateText(path))
{
sw.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
eve.Entry.Entity.GetType().Name, eve.Entry.State);
}
using (StreamWriter sw1 = File.CreateText("C:/error1.txt"))
foreach (var ve in eve.ValidationErrors)
{
sw1.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
ve.PropertyName, ve.ErrorMessage);
}
}
throw;
}
return StatusCode(HttpStatusCode.NoContent);
}
Same as WebApiConfig:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.Culture = new CultureInfo("ru-RU");
config.Formatters.Remove(config.Formatters.XmlFormatter);
}
There seems to be a typo (last ") in the request's Content-Type header:
Content-Type: application/json; charset=UTF-8"
When this header is missing or malformed, the server will automatically use application/octet-stream by default, as described by this post.
I were facing similar problem. Though i have a Content-Type declare it was still sending same error.
What I did is added Accept Header and it started working.
Accept: application/json
Content-Type: application/json
Also, make sure there's only one header Content-Type. In my case, my rest client was implicitly sending the empty Content-Type which got overridden by Content-Type: application/json hence the error.