I want to send file and json data from HttpClient to web api server.
I cant seem to access the json in the server via the payload, only as a json var.
public class RegulationFilesController : BaseApiController
{
public void PostFile(RegulationFileDto dto)
{
//the dto is null here
}
}
here is the client:
using (var client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
client.BaseAddress = new Uri(ConfigurationManager.AppSettings["ApiHost"]);
content.Add(new StreamContent(File.OpenRead(#"C:\\Chair.png")), "Chair", "Chair.png");
var parameters = new RegulationFileDto
{
ExternalAccountId = "1234",
};
JavaScriptSerializer serializer = new JavaScriptSerializer();
content.Add(new StringContent(serializer.Serialize(parameters), Encoding.UTF8, "application/json"));
var resTask = client.PostAsync("api/RegulationFiles", content); //?ApiKey=24Option_key
resTask.Wait();
resTask.ContinueWith(async responseTask =>
{
var res = await responseTask.Result.Content.ReadAsStringAsync();
}
);
}
}
this example will work:HttpClient Multipart Form Post in C#
but only via the form-data and not payload.
Can you please suggest how to access the file and the submitted json And the file at the same request?
Thanks
I have tried many different ways to submit both file data and metadata and this is the best approach I have found:
Don't use MultipartFormDataContent, use only StreamContent for the file data. This way you can stream the file upload so you don't take up too much RAM on the server. MultipartFormDataContent requires you to load the entire request into memory and then save the files to a local storage somewhere. By streaming, you also have the benefit of copying the stream into other locations such as an Azure storage container.
This solves the issue of the binary data, and now for the metadata. For this, use a custom header and serialize your JSON into that. Your controller can read the custom header and deserialize it as your metadata dto. There is a size limit to headers, see here (8-16KB), which is a large amount of data. If you need more space, you could do two separate requests, one to POST the minimum need, and then a PATCH to update any properties that needed more than a header could fit.
Sample code:
public class RegulationFilesController : BaseApiController
{
public async Task<IHttpActionResult> Post()
{
var isMultipart = this.Request.Content.IsMimeMultipartContent();
if (isMultipart)
{
return this.BadRequest("Only binary uploads are accepted.");
}
var headerDto = this.GetJsonDataHeader<RegulationFileDto>();
if(headerDto == null)
{
return this.BadRequest("Missing X-JsonData header.");
}
using (var stream = await this.Request.Content.ReadAsStreamAsync())
{
if (stream == null || stream.Length == 0)
{
return this.BadRequest("Invalid binary data.");
}
//save stream to disk or copy to another stream
var model = new RegulationFile(headerDto);
//save your model to the database
var dto = new RegulationFileDto(model);
var uri = new Uri("NEW URI HERE");
return this.Created(uri, dto);
}
}
private T GetJsonDataHeader<T>()
{
IEnumerable<string> headerCollection;
if (!this.Request.Headers.TryGetValues("X-JsonData", out headerCollection))
{
return default(T);
}
var headerItems = headerCollection.ToList();
if (headerItems.Count() != 1)
{
return default(T);
}
var meta = headerItems.FirstOrDefault();
return !string.IsNullOrWhiteSpace(meta) ? JsonConvert.DeserializeObject<T>(meta) : default(T);
}
}
Related
I did not able to store json response from API in sqflite database but i already parsed json response in list and also i stored similar data in sqflite database.
To stored locally i got success and able to perform CRUD operation and sending it to server, similarly i also able to perform CRUD operation on API data but problem arises on synchronization between local and json data.
the below code id for calling json data
Future<List<Activities>> getData() async {
List<Activities> list;
var res = await http
.post("http://xxxx/get-activity", headers: {
HttpHeaders.authorizationHeader: "Bearer " + _token.toString()
});
if (res.statusCode == 200) {
var data = json.decode(res.body);
var rest = data["data"] as List;
// print(rest);
list = rest.map<Activities>((json) => Activities.fromJson(json)).toList();
// print('okay, ${rest[0]}!');
} else {
print('something error');
}
print("List Size: ${list.length}");
return list;
}
solved
var data = json.decode(res.body);
var activities= data["data"] as List;
for (var activity in activities) {
Activity actData = Activity.fromMap(activity);
batch.insert(actTable, actData.toMap());
}
Solution! Please use this flutter plugin json_store
I am trying to insert data into the MongoDb collection using postman. How would I approach this; hardcoding the data in JSON format works, but I want to be able to insert using postman in JSON format.
This is the code that allowed me to enter directly, using the post function in postman, with no input:
public async void Insert([FromBody]string value)
{
var client = new MongoClient();
var dbs = client.GetDatabase("test");
var collection = dbs.GetCollection<BsonDocument> ("restaurants");
BsonArray dataFields = new BsonArray { new BsonDocument {
{ "ID" , ObjectId.GenerateNewId()}, { "_id", ""}, } };
var document = new BsonDocument
{
{"borough",value },
{"cuisine","Korean"},
{"name","Bellaa"},
{"restaurant_id","143155"}
};
await collection.InsertOneAsync(document);
}
You can send it as raw data. You will set the post type to application/json.
This comes From the docs.
I want upload a file (any type) on a server.
I have my file which is saved like this (I use FileAssociation)
await SharedStorageAccessManager.CopySharedFileAsync(ApplicationData.Current.LocalFolder, "fileToSave" + fileext, NameCollisionOption.ReplaceExisting, NavigationContext.QueryString["filetoken"]);
Then I get the saved file
StorageFolder folder = ApplicationData.Current.LocalFolder;
var file = await folder.GetFileAsync("fileToSave" + fileext);
Stream data = Application.GetResourceStream(new Uri(file.Path, UriKind.Relative)).Stream;
string filename = System.IO.Path.GetFileName(file.Path);
ServerFunctions.UploadFile(filename,data);
Then I start the Upload
internal void UploadFile(string fileName,Stream data)
{
WebClient web = new WebClient();
if (!string.IsNullOrEmpty(dataRequestParam.AuthentificationLogin))
{
System.Net.NetworkCredential account = new NetworkCredential(dataRequestParam.AuthentificationLogin, dataRequestParam.AuthentificationPassword);
web.Credentials = account;
}
web.AllowReadStreamBuffering = true;
web.AllowWriteStreamBuffering = true;
web.OpenWriteCompleted += (sender, e) =>
{
PushData(data, e.Result);
e.Result.Close();
data.Close();
};
web.OpenWriteAsync(dataRequestParam.TargetUri,"POST");
}
private void PushData(Stream input, Stream output)
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) != 0)
{
output.Write(buffer, 0, bytesRead);
}
}
The web server is supposed to send me as a response a xml with an error code or succes code inside.
None error is thrown but it doesnt work.And I don't understand why the e.result is a stream object. As I said the server should return a string...(xml file)
Could you bring me some explannations of what is happening in my code and if it will work with all types of files ?
Thanks
I think part of the problem here is that you're attempting to get this to behave like a streaming protocol when it seems you intend a request/response type architecture. For those purposes, you should consider working with a WebRequest object.
Bear with me as I fully qualify the namespace of the objects used inline, so it may get a little verbose, but I want you to know where to find these things.
internal async void UploadFile(string fileName, System.IO.Stream data)
{
// Specify URI, method, and credentials for the request
System.Net.WebRequest web = System.Net.HttpWebRequest.CreateHttp(dataRequestParam.TargetUri);
web.Method = "POST";
if (!string.IsNullOrEmpty(dataRequestParam.AuthenticationLogin))
{
web.Credentials = new System.Net.NetworkCredential(dataRequestParam.AuthenticationLogin, dataRequestParam.AuthenticationPassword);
}
// Create the request payload from the provided stream
System.IO.Stream requestStream =
await System.Threading.Tasks.Task<System.IO.Stream>.Factory.FromAsync(web.BeginGetRequestStream, web.EndGetRequestStream, null);
await data.CopyToAsync(requestStream);
// Get a response from the server
System.Net.WebResponse response =
await System.Threading.Tasks.Task<System.Net.WebResponse>.Factory.FromAsync(web.BeginGetResponse, web.EndGetResponse, null);
// Possibly parse the response with an XmlReader (example only)
System.Xml.XmlReader reader = System.Xml.XmlReader.Create(response.GetResponseStream());
string responseText = reader.ReadInnerXml(); // TODO: Real work here
}
The one oddity here is using the Task factory to create a task from the begin and end methods from getting both the request stream and the response. This makes it much simpler to consume these methods as you get a Task back which can be awaited for its return object, which you can then manipulate directly.
I'm not sure what form your response from the server takes on success versus failure, so I've simply shown how to create an XML reader to parse XML from the resulting stream. You can do whatever parsing is necessary yourself on these lines, but this should at least give you a look at what your server is returning in response.
The final code I use.
WebRequest web = HttpWebRequest.CreateHttp(dataRequestParam.TargetUri);
web.ContentType = dataRequestParam.ContentType;
web.Method = "POST";
web.ContentLength = data.Length;
if (!string.IsNullOrEmpty(dataRequestParam.AuthentificationLogin))
{
web.Credentials = new NetworkCredential(dataRequestParam.AuthentificationLogin, dataRequestParam.AuthentificationPassword);
}
using (var requestStream = await Task<Stream>.Factory.FromAsync(web.BeginGetRequestStream, web.EndGetRequestStream, web))
{
await data.CopyToAsync(requestStream);
}
WebResponse responseObject = await Task<WebResponse>.Factory.FromAsync(web.BeginGetResponse, web.EndGetResponse, web);
var responseStream = responseObject.GetResponseStream();
var sr = new StreamReader(responseStream);
string received = await sr.ReadToEndAsync();
return received;
}
How do i read HttpRequest data sent by POST method from client, on the server, in Dart?
I send a message from the client like this:
HttpRequest request = new HttpRequest();
var url = "http://127.0.0.1:8081";
request.open("POST", url, async: false);
String data = 'hello from client';
request.send(data);
On server i am catching the request like this:
HttpServer.bind('127.0.0.1', 8081).then((server) {
server.listen((HttpRequest request) {
//DATA SHOULD BE READ HERE
});
});
But i cant figure out how to actually read the data... There is not data property in HttpRequest nor anything else...
EDIT This is how i get the answer now:
HttpServer.bind('127.0.0.1', 8081).then((server) {
server.listen((HttpRequest request) {
//DATA SHOULD BE READ HERE
print("got it");
print(request.method);
if(request.method == "POST") {
print("got it 2");
List<int> dataBody = new List<int>();
request.listen(dataBody.addAll, onDone: () {
var postData = new String.fromCharCodes(dataBody);
print(postData);
});
}
});
});
But for some reason the request.method is not "POST" but "OPTIONS", and if i change to if(request.method == "OPTIONS") , then print(postData) will still return nothing...
You can use the StringDecoder to tranform from "List of Int" to "String" from the HttpRequest. Since no matter if you send json, plain text, or png, Dart always send data in form of
"List of Int" to the server.Another means is to use the Streams (http://www.dartlang.org/articles/feet-wet-streams/) tested on Heroku Steam v0.6.2 Dart Editor 0.4.3_r20602 Dat SDK 0.4.3.5_r26062
For example,
the client:
import 'dart:html';
import 'dart:json' as Json;
import 'dart:async';
import 'dart:uri';
final String data = 'Hello World!';
void _sendPNG(String pngData) {
HttpRequest request = new HttpRequest(); // create a new XHR
// add an event handler that is called when the request finishes
request.onReadyStateChange.listen((_)
{
if (request.readyState == HttpRequest.DONE &&
(request.status == 200 || request.status == 0)) {
// data saved OK.
print(request.responseText); // output the response from the server
}
}
);
// POST the data to the server Async
print('Sending Photos to the server...');
var url = "/png";
request.open("POST", url);
request.setRequestHeader("Content-Type", "text/plain");
request.send(data);
}
the server:
import 'dart:io';
import 'dart:async';
import 'dart:json' as Json;
import "package:stream/stream.dart";
import 'package:xml/xml.dart' as xml;
import 'package:unittest/unittest.dart';
import 'package:rikulo_commons/mirrors.dart';
void receivePNG(HttpConnect connect){
var request = connect.request;
var response = connect.response;
if(request.uri.path == '/png' && request.method == 'POST')
{
String png='';
response.write('The server received png request!');
//read incoming List<int> data from request and use StringDecoder to transform incoming data to string
var stream = request.transform(new StringDecoder());
stream.listen((value){
print(value);
//Hello World!
}
else
{
response.write('error');
response.statusCode = HttpStatus.NOT_FOUND;
connect.close();
}
}
configure.dart
var _mapping = {
"/": home,
"/png": receivePNG,
};
Right now, the handling of POST data is a little difficult. But essentially the HttpRequest itself has to be 'listened' to. HttpRequest is a stream itself. In particular it's a Stream<List<int>>. So basically your data may be passed to your HttpRequest as multiple List<int>'s. So we need to reconstruct the data then convert it into a string (assuming you're expecting a string, not binary data, etc). Here's more or less what I do:
HttpServer.bind('127.0.0.1', 8081).then((server) {
server.listen((HttpRequest request) {
if(request.method == "POST") {
List<int> dataBody = new List<int>();
request.listen(dataBody.addAll, onDone: () {
var postData = new String.fromCharCodes(dataBody);
// Do something with the data now.
});
}
request.response.close();
});
Note that the request.listen(dataBody.AddAll, ...) basically calls List.addAll() each time data is to the server (in cases of larger data or multi-part forms it may not come all at once). This ensures we buffer it all until the stream indicates it is 'done' In which case we can now do something with the data we received, like convert it to a string.
I have found this useful example with client/side code
GitHub json send to server Example
// XXX: Dart Editor thinks this is OK, but I haven't run it.
import 'dart:html';
String encodeMap(Map data) {
return data.keys.map((k) {
return '${Uri.encodeComponent(k)}=${Uri.encodeComponent(data[k])}';
}).join('&');
}
loadEnd(HttpRequest request) {
if (request.status != 200) {
print('Uh oh, there was an error of ${request.status}');
return;
} else {
print('Data has been posted');
}
}
main() {
var dataUrl = '/registrations/create';
var data = {'dart': 'fun', 'editor': 'productive'};
var encodedData = encodeMap(data);
var httpRequest = new HttpRequest();
httpRequest.open('POST', dataUrl);
httpRequest.setRequestHeader('Content-type',
'application/x-www-form-urlencoded');
httpRequest.onLoadEnd.listen((e) => loadEnd(httpRequest));
httpRequest.send(encodedData);
}
Anyone knows how to send the request using JSON content in windowsphone. I had the JSON parameters how to post it.
Simply serialize the data in JSON, and write it as a POST request to the server. Here's how I do it in one of my apps:
private static IObservable<T> GetDataAsync<T, TRequest>(TRequest input, string address)
{
var request = HttpWebRequest.Create(address);
request.Method = "POST";
var getRequestStream = Observable.FromAsyncPattern<Stream>(
request.BeginGetRequestStream,
request.EndGetRequestStream);
var getResponse = Observable.FromAsyncPattern<WebResponse>(
request.BeginGetResponse,
request.EndGetResponse);
return getRequestStream()
.SelectMany(stream =>
{
try
{
using (var writer = new StreamWriter(stream))
writer.WriteLine(JsonConvert.SerializeObject(input));
}
catch
{
// Intentionally ignored.
}
return getResponse();
})
.Select(webResponse =>
{
using (var reader = new StreamReader(webResponse.GetResponseStream()))
return JsonConvert.DeserializeObject<T>(reader.ReadToEnd());
});
}