Convert Curl command with WAV file to Unity web request - c#

Currently trying to convert a curl command to Unity Web request
Curl Command:
curl -H “x-app-key:APP_KEY_HERE“ /
-F " file=#AudioFile.wav" /
-F "user_token=USER_TOKEN_HERE" /
-F "category=orange" /
https://api.soapboxlabs.com/v1/speech/verification
And the code I've attempted:
private string url = "https://api.soapboxlabs.com/v1/speech/verification";
private string apiKey = "123456789";
void Start()
{
StartCoroutine(MakeSoapboxRequest());
}
IEnumerator MakeSoapboxRequest()
{
List<IMultipartFormSection> form = new List<IMultipartFormSection> {
new MultipartFormFileSection("file", "Assets\\Pilot1\\Audio\\soapbox_test.wav"),
new MultipartFormDataSection("user_token", "aaa1234567"),
new MultipartFormDataSection("category", "orange")
};
UnityWebRequest request = UnityWebRequest.Post(url, form);
request.SetRequestHeader("x-app-key", apiKey);
yield return request.SendWebRequest();
if(request.isNetworkError || request.isHttpError)
{
Debug.LogError(request.error);
}
else
{
Debug.Log("No soapbox error");
Debug.Log(request.downloadHandler.text);
}
}
Keep getting an error HTTP/1.1.400 Bad request
As you can see I've tried and commented out, WWW form as well. Is it something to do with me sending the wav file? I've tried looking into sending it as bytes but was left confused. The API I'm sending it to only takes wav files. It returns a JSON file. I'm just using the downloadHandler.text as a test.
Any help would be appreciated. I haven't used CURL before and it's my first time trying Unity Web Requests.

Note that the overload you are using for the file is MultiPartFormFileSection(string data, string fileName)
and states
data: Contents of the file to upload.
fileName: Name of the file uploaded by this form section.
So what happens here is: You are trying to upload "file" as the file content in an anonymous file section.
I think you should rather get the actual byte[] and rather use the overload MultipartFormFileSection(string name, byte[] data, string fileName, string contentType)
name Name of this form section.
data Raw contents of the file to upload.
fileName Name of the file uploaded by this form section.
contentType The value for this section's Content-Type header.
e
e.g. like
// Of course you would probably do these async before running the routine to avoid freeze
string yourFilePath;
var bytes = File.ReadAllBytes(yourFilePath);
new MultipartFormFileSection("file", bytes, "soapbox_test.wav", "application/octet-stream")
Finally note:
While a path like your given Assets\Pilot1\Audio\soapbox_test.wav might or might not work in the Unity Editor it will definitely fail in a build application!
You should either put your file into the StreamingAssets folder and access it via
var filePath = Path.Combine(Application.streamingAssetsPath, "fileName.extension");
or use the PersistentDataPath (you would of course have to make sure your file is stored there first)
var filePath = Path.Combine(Application.persistentDataPath, "fileName.extension");

Related

Receiving and working with a PDF/Image-File in an ASP.NET 6 API [duplicate]

I am using Insomnia for testing an API, but the same happens with Postman.
I want to test a file upload, with the following controller:
public async Task<IActionResult> Post([FromForm]IFormFile File)
If I set the request as a multipart request:
it works.
However, if I set it as a binary file:
I don't know how to get the data. How can it be done?
Also, in the controller method's signature, if I change [FromForm] to [FromBody], I'm not getting data.
Can someone clarify this for me?
As you've noticed already, using binary file option in Postman/Insomnia doesn't work the standard way. There are three different ways to upload file via RESTful API, and you have to choose one.
I've included code snippets that read the uploaded file contents to a string and output it -- try sending a text file, and you should get the contents of the file in the 200 response.
Form-data upload
This is the most popular/well-known upload method formatting the data you send as a set of key/value pairs. You normally need to specify Content-Type to multipart/form-data in the request, and then use [FromForm] attribute in MVC to bind values to variables. Also, you can use the built-in IFormFile class to access the file uploaded.
[HttpPost]
public async Task<IActionResult> PostFormData([FromForm] IFormFile file)
{
using (var sr = new StreamReader(file.OpenReadStream()))
{
var content = await sr.ReadToEndAsync();
return Ok(content);
}
}
Body upload
You can send body in the format that MVC understands, e.g. JSON, and embed the file inside it. Normally, the file contents would be encoded using Base64 or other encoding to prevent character encoding/decoding issues, especially if you are sending images or binary data. E.g.
{
"file": "MTIz"
}
And then specify [FromBody] inside your controller, and use class for model deserialization.
[HttpPost]
public IActionResult PostBody([FromBody] UploadModel uploadModel)
{
var bytes = Convert.FromBase64String(uploadModel.File);
var decodedString = Encoding.UTF8.GetString(bytes);
return Ok(decodedString);
}
// ...
public class UploadModel
{
public string File { get; set; }
}
When using large and non-text files, the JSON request becomes clunky and hard to read though.
Binary file
The key point here is that your file is the whole request. The request doesn't contain any additional info to help MVC to bind values to variables in your code. Therefore, to access the file, you need to read Body in the Request.
[HttpPost]
public async Task<IActionResult> PostBinary()
{
using (var sr = new StreamReader(Request.Body))
{
var body = await sr.ReadToEndAsync();
return Ok(body);
}
}
Note: the example reads Body as string. You may want to use Stream or byte[] in your application to avoid file data encoding issues.
In addition of the above, in case of multipart file conversion to base64String you can refer to the below:
if (File.Length> 0)
{
using (var ms = new MemoryStream())
{
File.CopyTo(ms);
var fileBytes = ms.ToArray();
string s = Convert.ToBase64String(fileBytes);
}
}
Note: I am using this code for .NET CORE 2.1

Asp.Net Core API receiving empty IFormFile

The last 2 days, I have been trying to create an image upload system for my website. When I try to save an uploaded image in the "wwwroot" of my Api, everything goes as planned except that I get an empty image in my folder.
At the backend, I receive the filename I send in the frontend but the bytes of the image itself are not there. For some reason the the data of the stream I put in the post call is missing but I do receive the filename in the formfile.
Edit:
To clear things up about my application, I'm working with an Asp.Net Mvc as frontend and Asp.Net Api as backend. I know this isn't how you are supposed to use Asp.Net but this is a school project and I have to do it like this. Normally i would work with Angular or something else but that is not an option for me right now.
So, I'm sending data from the Asp.Net Mvc (frontend) to the Asp.Net Api (backend) and I'm trying to do it by sending it as form data. That means there is no real form that is being submitted.
This is the guide I tried to use:
https://ilclubdellesei.blog/2018/02/14/how-to-upload-images-to-an-asp-net-core-rest-service-with-xamarin-forms/
Backend
ImageController:
[HttpPost("upload")]
public async Task<IActionResult> UploadImage([FromForm(Name = "file")] IFormFile file)
{
if (file.Length == 0)
return BadRequest("Empty file");
string imageName = file.FileName;
using (var fs = new FileStream("wwwroot/" + imageName, FileMode.Create, FileAccess.Write))
{
await file.CopyToAsync(fs);
}
return Ok();
}
Frontend
Method that uploads 1 image as a MemoryStream to the server
private async Task<string> Upload(Stream image, string name, string contentType)
{
_httpClient = _clientFactory.CreateClient("ProjectApi");
HttpContent fileStreamContent = new StreamContent(image);
fileStreamContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") { Name = "file", FileName = name };
fileStreamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileStreamContent);
HttpResponseMessage response = await _httpClient.PostAsync("api/images/upload", formData);
var input = await response.Content.ReadAsStringAsync();
return input;
}
}
The content doesn't seem to be empty:
The filename has been successfully send to the Api but the bytes of the image have not been send:
Structure after uploading some images without checking the size of the formfile (They are empty):
I am not 100% sure but I suppose the reason why you get empty file is that you did not set what type data your api endpoint will consume and maybe the form encryption type & method attributes. My suggestion is that you should update your code to below. ,
[Consumes("multipart/form-data")]
private async Task<string> Upload(Stream image, string name, string contentType)
And in case you forget to add form attributes to your html section, please set attributes as follows <form method="post" enctype="multipart/form-data">. Hope this solves your problem.

ASPNetCore - Uploading a file through REST

I am using Insomnia for testing an API, but the same happens with Postman.
I want to test a file upload, with the following controller:
public async Task<IActionResult> Post([FromForm]IFormFile File)
If I set the request as a multipart request:
it works.
However, if I set it as a binary file:
I don't know how to get the data. How can it be done?
Also, in the controller method's signature, if I change [FromForm] to [FromBody], I'm not getting data.
Can someone clarify this for me?
As you've noticed already, using binary file option in Postman/Insomnia doesn't work the standard way. There are three different ways to upload file via RESTful API, and you have to choose one.
I've included code snippets that read the uploaded file contents to a string and output it -- try sending a text file, and you should get the contents of the file in the 200 response.
Form-data upload
This is the most popular/well-known upload method formatting the data you send as a set of key/value pairs. You normally need to specify Content-Type to multipart/form-data in the request, and then use [FromForm] attribute in MVC to bind values to variables. Also, you can use the built-in IFormFile class to access the file uploaded.
[HttpPost]
public async Task<IActionResult> PostFormData([FromForm] IFormFile file)
{
using (var sr = new StreamReader(file.OpenReadStream()))
{
var content = await sr.ReadToEndAsync();
return Ok(content);
}
}
Body upload
You can send body in the format that MVC understands, e.g. JSON, and embed the file inside it. Normally, the file contents would be encoded using Base64 or other encoding to prevent character encoding/decoding issues, especially if you are sending images or binary data. E.g.
{
"file": "MTIz"
}
And then specify [FromBody] inside your controller, and use class for model deserialization.
[HttpPost]
public IActionResult PostBody([FromBody] UploadModel uploadModel)
{
var bytes = Convert.FromBase64String(uploadModel.File);
var decodedString = Encoding.UTF8.GetString(bytes);
return Ok(decodedString);
}
// ...
public class UploadModel
{
public string File { get; set; }
}
When using large and non-text files, the JSON request becomes clunky and hard to read though.
Binary file
The key point here is that your file is the whole request. The request doesn't contain any additional info to help MVC to bind values to variables in your code. Therefore, to access the file, you need to read Body in the Request.
[HttpPost]
public async Task<IActionResult> PostBinary()
{
using (var sr = new StreamReader(Request.Body))
{
var body = await sr.ReadToEndAsync();
return Ok(body);
}
}
Note: the example reads Body as string. You may want to use Stream or byte[] in your application to avoid file data encoding issues.
In addition of the above, in case of multipart file conversion to base64String you can refer to the below:
if (File.Length> 0)
{
using (var ms = new MemoryStream())
{
File.CopyTo(ms);
var fileBytes = ms.ToArray();
string s = Convert.ToBase64String(fileBytes);
}
}
Note: I am using this code for .NET CORE 2.1

How can I send a File over a REST API?

I am trying to send a file to a server over a REST API. The file could potentially be of any type, though it can be limited in size and type to things that can be sent as email attachments.
I think my approach will be to send the file as a binary stream, and then save that back into a file when it arrives at the server. Is there a built in way to do this in .Net or will I need to manually turn the file contents into a data stream and send that?
For clarity, I have control over both the client and server code, so I am not restricted to any particular approach.
I'd recommend you look into RestSharp
http://restsharp.org/
The RestSharp library has methods for posting files to a REST service. (RestRequst.AddFile()). I believe on the server-side this will translate into an encoded string into the body, with the content-type in the header specifying the file type.
I've also seen it done by converting a stream to a base-64 string, and transferring that as one of the properties of the serialized json/xml object. Especially if you can set size limits and want to include file meta-data in the request as part of the same object, this works really well.
It really depends how large your files are though. If they are very large, you need to consider streaming, of which the nuances of that is covered in this SO post pretty thoroughly: How do streaming resources fit within the RESTful paradigm?
You could send it as a POST request to the server, passing file as a FormParam.
#POST
#Path("/upload")
//#Consumes(MediaType.MULTIPART_FORM_DATA)
#Consumes("application/x-www-form-urlencoded")
public Response uploadFile( #FormParam("uploadFile") String script, #HeaderParam("X-Auth-Token") String STtoken, #Context HttpHeaders hh) {
// local variables
String uploadFilePath = null;
InputStream fileInputStream = new ByteArrayInputStream(script.getBytes(StandardCharsets.UTF_8));
//System.out.println(script); //debugging
try {
uploadFilePath = writeToFileServer(fileInputStream, SCRIPT_FILENAME);
}
catch(IOException ioe){
ioe.printStackTrace();
}
return Response.ok("File successfully uploaded at " + uploadFilePath + "\n").build();
}
private String writeToFileServer(InputStream inputStream, String fileName) throws IOException {
OutputStream outputStream = null;
String qualifiedUploadFilePath = SIMULATION_RESULTS_PATH + fileName;
try {
outputStream = new FileOutputStream(new File(qualifiedUploadFilePath));
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
outputStream.flush();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
finally{
//release resource, if any
outputStream.close();
}
return qualifiedUploadFilePath;
}
Building on to #MutantNinjaCodeMonkey's suggestion of RestSharp. My use case was posting webform data from jquery's $.ajax method into a web api controller. The restful API service required the uploaded file to be added to the request Body. The default restsharp method of AddFile mentioned above caused an error of The request was aborted: The request was canceled. The following initialization worked:
// Stream comes from web api's HttpPostedFile.InputStream
(HttpContext.Current.Request.Files["fileUploadNameFromAjaxData"].InputStream)
using (var ms = new MemoryStream())
{
fileUploadStream.CopyTo(ms);
photoBytes = ms.ToArray();
}
var request = new RestRequest(Method.PUT)
{
AlwaysMultipartFormData = true,
Files = { FileParameter.Create("file", photoBytes, "file") }
};
Detect the file/s being transported with the request.
Decide on a path where the file will be uploaded (and make sure CHMOD 777 exists for this directory)
Accept the client connect
Use ready library for the actual upload
Review the following discussion:
REST file upload with HttpRequestMessage or Stream?
First, you should login to the server and get an access token.
Next, you should convert your file to stream and post the stream:
private void UploadFile(FileStream stream, string fileName)
{
string apiUrl = "http://example.com/api";
var formContent = new MultipartFormDataContent
{
{new StringContent(fileName),"FileName"},
{new StreamContent(stream),"formFile",fileName},
};
using HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Authorization", accessToken);
var response = httpClient.PostAsync(#$"{apiUrl}/FileUpload/save", formContent);
var result = response.Result.Content.ReadAsStringAsync().Result;
}
In this example, we upload the file to http://example.com/api/FileUpload/save and the controller has the following method in its FileUpload controller:
[HttpPost("Save")]
public ActionResult Save([FromForm] FileContent fileContent)
{
// ...
}
public class FileContent
{
public string FileName { get; set; }
public IFormFile formFile { get; set; }
}

C# file uploading with a string using on PHP server

I am uploading a file with C# code on php server. But facing some issues.
First I was using a WebClient Object to upload file by calling UploadFile() method, and uploading string to by calling UploadString() method by following code:
String StoreID = "First Store";
WebClient Client = new WebClient();
String s = Client.UploadString("http://localhost/upload.php", "POST", StoreID);
Client.Headers.Add("Content-Type","binary/octet-stream");
byte[] result = Client.UploadFile("http://localhost/upload.php", "POST", "C:\\aaaa.jpg");
s = s + System.Text.Encoding.UTF8.GetString(result,0,result.Length);
Issue is that I am requesting two times so string and file is not being send at same time. I am receiving either String or File. But I need both at same time. I don't want to use UploadData() becuase it will use byte codes and I have know I idea how to extract it in php.
Let that string is folder name, i have to send string and file, so that file could save at specified folder at php server.
I studied there may be a solution with WebRequest and WebResponse object. But dont know how to send request using WebResponse by C# and get it at PHP.
Any Suggestions!!!!
Try this :
WebClient web = new WebClient();
try{
web.UploadFile("http://" + ip + "/test.php", StoreID);
}
catch(Exception e)
{
MessageBox.Show("Upload failed");
}
Now you can access the file from the PHP file.
<?php
//check whether the folder the exists
if(!(file_exists('C:/Users/dhanu-sdu/Desktop/test')))
{
//create the folder
mkdir('C:/Users/ComputerName/Desktop/test');
//give permission to the folder
chmod('C:/Users/ComputerName/Desktop/test', 0777);
}
//check whether the file exists
if (file_exists('C:/Users/ComputerName/Desktop/test/'. $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " already exists. ";
}
else
{
//move the file into the new folder
move_uploaded_file($_FILES["file"]["tmp_name"],'C:/Users/ComputerName/Desktop/test/'. $_FILES["file"]["name"]);
}
?>
Also, you can download data from a PHP server and display it in a C# web browser by using the following codes :
WebClient web = new WebClient();
try{
byte[] response = web.DownloadData("http://" + ip +"/test.php");
webBrowser1.DocumentText = System.Text.ASCIIEncoding.ASCII.GetString(response);
}
catch(Exception e)
{
MessageBox.Show("Download failed");
}
You can create a webservice with php that accepts a file. Then publish that webservice, and add it to you c# references, then just call teh method from within your c# code that accepts the file, and vualá!
How to create SOAP with php link

Categories

Resources