I am using the Flutter Plugin Image_picker to choose images so that I want to upload image after selected the image
Future<File> _imageFile;
void _onImageButtonPressed(ImageSource source) async {
setState(() {
_imageFile = ImagePicker.pickImage(source: source);
});
}
I find this code in flutter documentation but its not work
var uri = Uri.parse("http://pub.dartlang.org/packages/create");
var request = new http.MultipartRequest("POST", url);
request.fields['user'] = 'nweiz#google.com';
request.files.add(new http.MultipartFile.fromFile(
'package',
new File('build/package.tar.gz'),
contentType: new MediaType('application', 'x-tar'));
request.send().then((response) {
if (response.statusCode == 200) print("Uploaded!");
});
Use MultipartRequest class
Upload(File imageFile) async {
var stream = new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
var length = await imageFile.length();
var uri = Uri.parse(uploadURL);
var request = new http.MultipartRequest("POST", uri);
var multipartFile = new http.MultipartFile('file', stream, length,
filename: basename(imageFile.path));
//contentType: new MediaType('image', 'png'));
request.files.add(multipartFile);
var response = await request.send();
print(response.statusCode);
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
Check this answer
This code works properly.
Used MultipartRequest class
void uploadImage() async {
File _image;
File pickedImage = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = pickedImage;
});
// open a byteStream
var stream = new http.ByteStream(DelegatingStream.typed(_image.openRead()));
// get file length
var length = await _image.length();
// string to uri
var uri = Uri.parse("enter here upload URL");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// if you need more parameters to parse, add those like this. i added "user_id". here this "user_id" is a key of the API request
request.fields["user_id"] = "text";
// multipart that takes file.. here this "image_file" is a key of the API request
var multipartFile = new http.MultipartFile('image_file', stream, length, filename: basename(_image.path));
// add file to multipart
request.files.add(multipartFile);
// send request to upload image
await request.send().then((response) async {
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}).catchError((e) {
print(e);
});
}
name spaces:
import 'package:path/path.dart';
import 'package:async/async.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
If you want the uploading function to return the server response, you can use toBytes() instead of transform(), in order to wait until data transmission is complete.
Future<String> upload() async {
String responseString = '';
// Pick image
final image = await ImagePicker().getImage(
source: ImageSource.gallery // or ImageSource.camera
imageQuality: 100,
maxWidth: 1000,
);
// Convert to File
final file = File(image.path);
// Set URI
final uri = Uri.parse('URL');
// Set the name of file parameter
final parameter = 'Name';
// Upload
final request = http.MultipartRequest('POST', uri)
..files.add(await http.MultipartFile.fromPath(parameter, file.path));
final response = await request.send();
if (response.statusCode == 200) {
responseString = String.fromCharCodes(await response.stream.toBytes());
}
return responseString;
}
Related
We have middleware in a web API, which we use to filter the resposne body from a controller
After updating our service to .net 5, replacing the output fails with
System.InvalidOperationException: Headers already sent.
at Microsoft.AspNetCore.Server.HttpSys.Response.CheckResponseStarted()
at Microsoft.AspNetCore.Server.HttpSys.FeatureContext.ConsiderEnablingResponseCache()
at Microsoft.AspNetCore.Server.HttpSys.FeatureContext.OnResponseStart()
at Microsoft.AspNetCore.Server.HttpSys.FeatureContext.CompleteAsync()
at Microsoft.AspNetCore.Server.HttpSys.RequestContext.Execute()
at Microsoft.AspNetCore.Server.HttpSys.RequestContext.Execute()
Our middleware to filter the output looks something like this
internal class FilterOutput : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var originalBodyStream = context.Response.Body;
var tempResponseBody = new MemoryStream();
context.Response.Body = tempResponseBody;
context.Response.OnStarting(async state =>
{
await FilterResponse(context, tempResponseBody, originalBodyStream);
}, context);
await next(context);
}
private async Task FilterResponse(HttpContext context, MemoryStream tempResponseBody, Stream originalBodyStream)
{
if (context.Response.StatusCode == 200)
{
var output = Encoding.UTF8.GetString(tempResponseBody.GetBuffer());
var newOutput = output.Filter(null);
var updatedStream = GenerateStreamFromString(newOutput);
await updatedStream.CopyToAsync(originalBodyStream);
context.Response.Body = originalBodyStream;
return;
}
await tempResponseBody.CopyToAsync(originalBodyStream);
}
public static Stream GenerateStreamFromString(string s)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
}
I realize net 5 is propably more asynchronous and sends headers earlier
Is there a way to stop that, so I can modify the output body in middleware?
Here is my code:
Future<String> fetch(url) async {
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
var cj = new PersistCookieJar(tempPath);
HttpClient client = new HttpClient();
var request = await client.getUrl(Uri.parse(url));
request.cookies.addAll(cj.loadForRequest(Uri.parse(url)));
var response = await request.close();
cj.saveFromResponse(Uri.parse(url), response.cookies);
// I tried using .toString() but it returns an " Instance of '_HttpClientResponse' "
return response.toString();
}
I tried for hours to find a way to return the response body, but without any success, could someone please help me.
Never mind, I fixed it.
I used this code:
Future<String> fetch(url) async {
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
var cj = new PersistCookieJar(tempPath);
HttpClient client = new HttpClient();
var request = await client.getUrl(Uri.parse(url));
request.cookies.addAll(cj.loadForRequest(Uri.parse(url)));
var response = await request.close();
cj.saveFromResponse(Uri.parse(url), response.cookies);
// I had to transform the response for it to work
var body = await response.transform(Utf8Decoder(allowMalformed: true)).join();
return body;
}
I have a multiword String that I'd like to convert to a GET request parameter.
I have an API endpoint /search that takes in the parameter query. Now typically your request would look like http://host/search?query=Hello+World.
I have a String Hello World that I'd like to convert to this URL encoded parameter.
Ofcourse, I could just write the logic to break it into words and add a + in between but I was wondering if the URI class could help with this
I'm using Dart's httpClient to make a request.
Future<String> _getJsonData(String queryToSearch) async {
List data = new List();
var httpClient = new HttpClient();
var request = await httpClient.getUrl(Uri.parse(
config['API_ENDPOINT'] + '/search?query=' +
queryToSearch));
var response = await request.close();
if (response.statusCode == HttpStatus.OK) {
var jsonString = await response.transform(utf8.decoder).join();
data = json.decode(jsonString);
print(data[0]);
return data[0].toString();
} else {
return "{}";
}
}
Essentially, need to encode queryToSearch as the URL parameter.
You can use Uri.http(s) which wrap everythings (query, host, and path) together and encode them accordingly.
final uri = new Uri.http(config['API_ENDPOINT'], '/search', {"query": queryToSearch});
The Uri class provides methods for that
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeQueryComponent.html
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeFull.html
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeComponent.html
You can use Uri.parse(url_string) if you have the full URL in this way.
final String accountEndPoint = 'https://api.npoint.io/2e4ef87d9ewqf01e481e';
Future<Account> getAccountData() async {
try {
final uri = Uri.parse(accountEndPoint); // <===
final response = await http.get(uri);
if (response.statusCode == 200) {
Map<String, dynamic> accountJson = jsonDecode(response.body);
return Future.value(Account.fromJson(accountJson));
} else {
throw Exception('Failed to get account');
}
} catch (e) {
return Future.error(e);
}
}
I am calling an api. I am getting a streamed response after sending the request. But i cannot parse the response and convert it to String/JSON. This is where I am calling the api.
static Future<String> callDeviceListFetchApi() async {
Completer completer = new Completer();
String jsonResponse;
String url = Constants.BASE_URL + Constants.DEVICE_REGISTER_URL;
var client = new http.Client();
var request = new http.Request('GET', Uri.parse(url));
request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json';
request.headers[HttpHeaders.AUTHORIZATION] = '<auth code>';
await client.send(request).then((response) {
response.stream.bytesToString().then((value) {
print(value.toString());
jsonResponse = value.toString();
completer.complete(jsonResponse);
});
}).catchError((error) {
print(error.toString());
});
return completer.future;
}
I am getting the error,
Bad state: Stream has already been listened to Flutter error. Any idea why this is happening?
There's a couple of things wrong with your code. I think you have a slight misunderstanding about how Async and Futures work in dart - you should re-read the docs and this tutorial (part 1 and part 2).
Basically, the problem is that you were returning a 'Future' from an async function. If you return a future from an async function, it has issues (I don't know why the analyzer doesn't catch that).
Future<String> callDeviceListFetchApi() async {
Completer completer = new Completer();
String url = "<url>";
var client = new http.Client();
var request = new http.Request('GET', Uri.parse(url));
request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json';
request.headers[HttpHeaders.AUTHORIZATION] =
'<auth string>';
var response = await client.send(request);
String jsonResponse;
try {
var value = await response.stream.bytesToString();
print(value.toString());
jsonResponse = value.toString();
} catch (error) {
print(error.toString());
}
return completer.complete(jsonResponse);
}
Or not async:
Future<String> callDeviceListFetchApiNotAsync() {
String url = "<url>";
var client = new http.Client();
var request = new http.Request('GET', Uri.parse(url));
request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json';
request.headers[HttpHeaders.AUTHORIZATION] =
'<auth string>';
Completer completer = new Completer();
return client.send(request).then((response) {
return response.stream.bytesToString();
}).then((value) {
print(value.toString());
return value.toString();
}).catchError((error) {
print(error.toString());
// if you use catchError, whatever you return from it
// is the value you'll get wherever you resolve the future.
return null;
});
}
But unless you're trying to do something I'm not seeing, there's a way easier way to do this (assuming all you want to do is get a string from a server):
Future<String> getList() async {
var response = await http.get("<url>", headers: {
HttpHeaders.CONTENT_TYPE: 'application/json',
HttpHeaders.AUTHORIZATION: '<auth string>',
});
if (response.statusCode == 200) {
return response.body;
} else {
throw Error();
}
}
I have included a link on my website to download images. When I click on the link I would like the download to automatically start.
Currently when I click on the link I’m getting back the response message: Example:
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.PushStreamContent, Headers: { Content-Type: application/octet-stream Content-Disposition: attachment; filename=895621d7-57a4-47a5-8dc5-ae36a2623826Banneraaaaaaaa.jpg }
How do I modify the code below to start the download automatically. I think I might be returning the wrong type:
Here is my code:
public HttpResponseMessage DownloadImageFile(string filepath)
{
filepath = "https://mysite.com/" + filepath;
try
{
var response = new HttpResponseMessage();
response.Content = new PushStreamContent((Stream outputStream, HttpContent content, TransportContext context) =>
{
try
{
DownloadFile(filepath, outputStream);
}
finally
{
outputStream.Close();
}
});
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = Path.GetFileName(filepath);
return response;
}
catch (Exception ex)
{
}
return null;
}
public void DownloadFile(string file, Stream response)
{
var bufferSize = 1024 * 1024;
using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
var buffer = new byte[bufferSize];
var bytesRead = 0;
while ((bytesRead = stream.Read(buffer, 0, bufferSize)) > 0)
{
response.Write(buffer, 0, bytesRead);
}
response.Flush();
}
}
}
You should use one of the Controller.File overload. The File() helper method provides support for returning the contents of a file. The MediaTypeNames class can be used to get the MIME type for a specific file name extension.
For example:
public FileResult Download(string fileNameWithPath)
{
// Option 1 - Native support for file read
return File(fileNameWithPath, System.Net.Mime.MediaTypeNames.Application.Octet, Path.GetFileName(fileNameWithPath));
// Option 2 - Read byte array and pass to file object
//byte[] fileBytes = System.IO.File.ReadAllBytes(fileName); return
//File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet,
//fileName);
}