Error uploading file in Dart to Redstone Server - dart

I am trying to upload a file in Dart with this code
Reading the file
dom.InputElement uploadInput = dom.querySelector('#upload');
uploadInput.onChange.listen((dom.Event e)
{
// read file content as dataURL
final files = uploadInput.files;
if (files.length == 1)
{
final file = files[0];
final reader = new dom.FileReader();
reader.onLoad.listen((_)
{
dataRequest('upload', reader.result);
});
reader.readAsDataUrl (file);
}
});
Sending the file
Future<dom.HttpRequest> dataRequest (String path, dynamic data)
{
return dom.HttpRequest.request (path, method: "POST",
sendData: data);
}
But I get this error
POST http://localhost:9090/upload 400 (Bad Request) :9090/upload:1
Instance of '_XMLHttpRequestProgressEvent'
STACKTRACE:
null
I receive it in Redstone like this
#app.Route("/upload", methods: const [app.POST], allowMultipartRequest: true)
#Encode()
upload(#app.Body(app.FORM) Map form)
{
var file = form["file"];
print(file.filename);
print(file.contentType);
print(file.runtimeType);
return new Resp()
..success = (file.filename != null);
}
Any ideas?

Dart: 1.9.1
Redstone: 0.5.21
Let's say you have the following html:
<!DOCTYPE html>
<html>
<head>
<title>send_file.html</title>
</head>
<body>
<form id="read">
user: <input type="text" name='user' value='DefaultValue'>
<input type="file" id="file" name="my_file"/> <br>
<input type="button" id="whole_btn" value="Send whole form!">
<input type="button" id="specific_btn" value="Send specific values!">
</form>
<script type="application/dart" src="send_file.dart"></script>
</body>
</html>
Redstone server file:
import 'dart:io';
import 'package:logging/logging.dart';
import 'package:redstone/server.dart' as app;
import 'package:shelf_static/shelf_static.dart';
#app.ErrorHandler(HttpStatus.NOT_FOUND)
handleNotFoundError() => app.redirect("not_found.html");
#app.Route('/post',methods: const [app.POST], allowMultipartRequest: true)
wholeFormPost(#app.Body(app.FORM) Map form) {
var user = form['user'];
var f = form['my_file'];
print('user: $user \n file: \n ${f.content}');
}
#app.Route('/post1',methods: const [app.POST], allowMultipartRequest: true)
specificPost(#app.Body(app.FORM) Map form) {
var specificField = form['specificField'];
var f = form['my_file'];
print('specificField: $specificField \n file: \n ${f.content}');
}
#app.Interceptor(r'/.*')
interceptor1() {
if (app.request.method == 'OPTIONS') {
app.response = app.response.change(headers: CORS);
app.chain.interrupt();
} else {
app.chain.next(() {
return app.response = app.response.change(headers: CORS );
});
}
}
Map CORS = {
"Access-Control-Allow-Origin" : "*, ",
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
"Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept, Content-Disposition"
};
main() {
app.setShelfHandler(createStaticHandler("/home/raz2/dartProjects_linux_1/PR5/cl2/lib",
defaultDocument: 'send_file.html',
serveFilesOutsidePath: true));
app.setupConsoleLog(Level.ALL);
app.start(address: "0.0.0.0", port: 8081);
}
The client dart file: send_file.dart
import 'dart:html';
class UploadFileEx {
FormElement _readForm;
InputElement _fileInput;
File file;
ButtonElement _wholeBtn;
ButtonElement _specificBtn;
UploadFileEx() {
_readForm = document.querySelector('#read');
_fileInput =
document.querySelector('#file')
..onChange.listen(_onFileInputChange);
_wholeBtn =
document.querySelector('#whole_btn')
..onClick.listen((sendForm));
_specificBtn =
document.querySelector('#specific_btn')
..onClick.listen((sendFileAndField));
}
_onFileInputChange(_) {
file = _fileInput.files[0];
}
// Send the whole form
void sendForm(_) {
if(file == null)
return;
FormData fd = new FormData(_readForm);
HttpRequest req = new HttpRequest();
req.open("POST", 'http://127.0.0.1:8081/post');
req.send(fd);
}
// add my own field to FormData
void sendFileAndField(_) {
if(file == null)
return;
FormData fd = new FormData();
fd.append('specificField', 'Lalala');
fd.appendBlob('my_file', file);
HttpRequest req = new HttpRequest();
req.open("POST",'http://127.0.0.1:8081/post1');
req.send(fd);
}
}
void main() {
new UploadFileEx();
}
Should work.
Check out this link for more info: Sending_forms_through_JavaScript

Related

uploading file using input field

I created a web app using asp.net-mvc and Jquery
when I added the below code my application automatically stop running without throwing any error, I don't know Whether it is my visual studio 19 or IIS which is being crashed
<label for="myfile">Select a file:</label>
<input type="file" id="myfile" name="myfile">
To verify I created an asp.net mvc sample project and paste the above code in the index page but the same problem comes
Image
what can I do to solve this?
Do you have
enctype="multipart/form-data"
property in your form element?
<form id="upload">
<input type="file" id="file" class="form-control">
</form>
Jquery
$('#upload').submit(function (e) {
e.preventDefault(); // stop the standard form submission
var File_Name = $("#file").prop('files')[0].name;
var ext = File_Name.split('.').pop();
if (ext == "pdf" || ext == "docx" || ext == "doc" || ext == "png" || ext ==
"jpg" || ext == "jpeg" || ext == "txt") {
var lastIndex = $("#file").prop('files')[0].name.lastIndexOf(".") + 1;
var form = new FormData();
form.append("file", $("#file").prop('files')[0]);
$.ajax({
url: '/Main/SaveDocument',
type: 'POST',
data: form,
cache: false,
contentType: false,
processData: false,
success: function (data) {
console.log(data.UploadedFileCount + ' file(s) uploaded successfully');
if (data == "999") {
swal("Note", "Some Error Occurred. File Not uploaded successfully.", "error");
}
},
error: function (xhr, error, status) {
console.log(error, status + " " + xhr);
}
});
}
else {
swal("Note", "File Type Not Supported.", "warning");
}
});
C#
public ActionResult SaveDocument()
{
//file
var file = System.Web.HttpContext.Current.Request.Files["file"];
var CheckCnic = hr_FTPEntities.File_description.Where(x => x.uploader_CNIC == userCNIC).FirstOrDefault();
if(CheckCnic == null)
{
HttpPostedFileBase filebase = new HttpPostedFileWrapper(file);
if (filebase.ContentLength > 0)
{
var fileName = Path.GetFileName(filebase.FileName);
string path = Path.Combine(Server.MapPath(basePath + departmentName) + "/");
File_description file_Description = new File_description();
int fileCount = hr_FTPEntities.File_description.Select(x => x).ToList().Count + 1;
int lastIndexOfDot = fileName.LastIndexOf(".") - 1;
string finalFileName = fileName.Substring(0, lastIndexOfDot) + "_" + fileCount + fileName.Substring(lastIndexOfDot + 1);
file_Description.file_name = finalFileName.ToString();
try
{
filebase.SaveAs(path + (finalFileName));
}
catch(Exception ex)
{
return Json("999");
}
}
return Json("000");
}
else
{
return Json("888");
}
}
You could try to use the below code:
View(Index.cshtml) :
<input type="file" id="FileUpload1" />
<input type="button" id="btnUpload" value="Upload Files" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
$(document).ready(function(){
$('#btnUpload').click(function () {
// Checking whether FormData is available in browser
if (window.FormData !== undefined) {
var fileUpload = $("#FileUpload1").get(0);
var files = fileUpload.files;
// Create FormData object
var fileData = new FormData();
// Looping over all files and add it to FormData object
for (var i = 0; i < files.length; i++) {
fileData.append(files[i].name, files[i]);
}
// Adding one more key to FormData object
fileData.append('username', 'test');
$.ajax({
url: '/Home/UploadFiles',
type: "POST",
contentType: false, // Not to set any content header
processData: false, // Not to process data
data: fileData,
success: function (result) {
alert(result);
},
error: function (err) {
alert(err.statusText);
}
});
} else {
alert("FormData is not supported.");
}
});
});
</script>
Controller (HomeController.cs):
[HttpPost]
public ActionResult UploadFiles()
{
// Checking no of files injected in Request object
if (Request.Files.Count > 0)
{
try
{
// Get all files from Request object
HttpFileCollectionBase files = Request.Files;
for (int i = 0; i < files.Count; i++)
{
//string path = AppDomain.CurrentDomain.BaseDirectory + "Uploads/";
//string filename = Path.GetFileName(Request.Files[i].FileName);
HttpPostedFileBase file = files[i];
string fname;
// Checking for Internet Explorer
if (Request.Browser.Browser.ToUpper() == "IE" || Request.Browser.Browser.ToUpper() == "INTERNETEXPLORER")
{
string[] testfiles = file.FileName.Split(new char[] { '\\' });
fname = testfiles[testfiles.Length - 1];
}
else
{
fname = file.FileName;
}
// Get the complete folder path and store the file inside it.
fname = Path.Combine(Server.MapPath("~/Uploads/"), fname);
file.SaveAs(fname);
}
// Returns message that successfully uploaded
return Json("File Uploaded Successfully!");
}
catch (Exception ex)
{
return Json("Error occurred. Error details: " + ex.Message);
}
}
else
{
return Json("No files selected.");
}
}
Make sure your IIS site contains the upload folder and enough permission to access the folder.
If you still face the same issue then try to use the different browser.
check event viewer logs or try to collect the dup and analyze the dump using the DebugDiag tool.

Image Upload using MVC API POST Multipart form

My View :-
<form class="commentform commentright" enctype="multipart/form-data" >
<textarea class="simpleta required" name="Body" placeholder="Discuss this vehicle with other members of Row52."></textarea>
<input type="file" id="fileuploadfield" name="fileuploadfield"/>
<input type="submit" value="Submit" class="btn btn-inverse btn-small"/>
<input type="hidden" name="ParentId" value="0"/>
<input type="hidden" name="VehicleId" value="#Model.VehicleId"/>
<span class="commentcount"><span class="numberofcomments">#Model.Count</span>#count</span>
<div class="feedback"></div>
<img id="img" src="" />
</form>
JQuery :-
submitComment: function (form, type) {
var self = this;
var $this = $(form);
var formData = $this.serialize();
var $message = $this.find('.feedback');
$message.hide();
$message.html('');
var val = validation({ $form: $this });
if (val.checkRequired()) {
$this.indicator({ autoStart: false, minDuration: 100 });
$this.indicator('start');
var files = $("#fileuploadfield").get(0).files;
if (files.length > 0) {
if (window.FormData !== undefined) {
var data = new FormData();
for (var i = 0; i < files.length; i++) {
data.append("file" + i, files[i]);
}
}
else {
alert("This browser doesn't support HTML5 multiple file uploads!");
}
}
else {
alert("This");
}
$.ajax('/api/v2/comment/Post/', {
type: 'POST',
contentType: 'multipart/form-data',
// I have also use contentType: false,
processData: false,
data: formData
}).done(function (d) {
Controller :-
public Task<HttpResponseMessage> Post()
{
var provider = new MultipartMemoryStreamProvider();
var task1 = Request.Content.ReadAsMultipartAsync(provider);
var userId = User.Id;
return task1.Then(providerResult =>
{
var file = GetFileContent(providerResult);
var task2 = file.ReadAsStreamAsync();
string originalFileName = file.Headers.ContentDisposition.FileName.Replace("\"", "");
string extension = Path.GetExtension(originalFileName);
string fileName = Guid.NewGuid().ToString() + extension;
return task2.Then(stream =>
{
if (stream.Length > 0)
{
var kernel = WindsorContainerFactory.Create(KernelState.Thread, ConfigurationState.Web);
CloudBlobContainer container = GetContainer();
var userRepo = kernel.Resolve<IUserRepository>();
var logger = kernel.Resolve<ILogger>();
logger.Fatal("Original File Name: " + originalFileName);
logger.Fatal("Extension: " + extension);
logger.Fatal("File Name: " + fileName);
var user = userRepo.FirstOrDefault(x => x.Id == userId);
var path = CreateImageSize(stream, 500, fileName, userId, container, logger);
if (user != null)
{
user.AvatarOriginalFileName = fileName;
user.AvatarOriginalAbsolutePath =
ConfigurationManager.AppSettings["CdnUserEndpointUrl"] + path;
user.AvatarOriginalRelativePath = path;
user.AvatarCroppedAbsolutePath = "";
user.AvatarCroppedFileName = "";
user.AvatarCroppedRelativePath = "";
userRepo.Update(user);
}
else
{
Logger.Error("User is null. Id: " + userId.ToString());
}
kernel.Release(userRepo);
kernel.Release(logger);
kernel.Dispose();
}
var response = Request.CreateResponse(HttpStatusCode.Moved);
response.Headers.Location = new Uri("/Account/Avatar", UriKind.Relative);
return response;
});
});
}
Following Error get :-
"Invalid 'HttpContent' instance provided. It does not have a content type header starting with 'multipart/'. Parameter name: content"
There's no standard Task.Then method in .NET framework, and I couldn't find any implementation details in the code you posted. I'd assume it was taken from here:
Processing Sequences of Asynchronous Operations with Tasks
If that's the case, you may be loosing AspNetSynchronizationContext context inside your Task.Then lambdas, because the continuation may happen on a different ASP.NET pool thread without proper synchronization context. That would explain why HttpContent becomes invalid.
Try changing the implementation of Task.Then like this:
public static Task<T2> Then<T1, T2>(this Task<T1> first, Func<T1, Task<T2>> next)
{
if (first == null) throw new ArgumentNullException("first");
if (next == null) throw new ArgumentNullException("next");
var tcs = new TaskCompletionSource<T2>();
first.ContinueWith(delegate
{
if (first.IsFaulted) tcs.TrySetException(first.Exception.InnerExceptions);
else if (first.IsCanceled) tcs.TrySetCanceled();
else
{
try
{
var t = next(first.Result);
if (t == null) tcs.TrySetCanceled();
else t.ContinueWith(delegate
{
if (t.IsFaulted) tcs.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCanceled) tcs.TrySetCanceled();
else tcs.TrySetResult(t.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
}
catch (Exception exc) { tcs.TrySetException(exc); }
}
}, TaskScheduler.FromCurrentSynchronizationContext());
return tcs.Task;
}
Note how the continuations are now scheduled using TaskScheduler.FromCurrentSynchronizationContext().
Ideally, if you can use .NET 4.5, you should be using async/await: Using Asynchronous Methods in ASP.NET 4.5. This way, the thread's synchronization context is automatically captured for await continuations.
The following may facility porting:
Implementing Then with Await.

sending form data xmlhttprequest

In below code first am allowing the user to select the option from the drop down list and than allows to browse the file.
Code:
function choice() {
var box = dhtmlx.modalbox({
text: "<div id='form_in_box'><div>Choose a File to Convert <hr/><label>Filename: <input type='file' name='file' id='file' style='width: 400px; height: 27px;'></label><br></div><div><span class='dhtmlx_button'><input type='submit' value='Create PDF' style='width: 86px' onclick='Convert(this)'></span><span class='dhtmlx_button'><input type='button' value='Cancel' onclick='close_file(this)' style='width:80px;'></span></label></div></div>",
width: "300px"
});
}
function Convert(box) {
var ch = document.getElementById('choice');
var file = document.getElementById('file');
if (file.value == "") {
alert("Choose a file to convert");
return false;
}
dhtmlx.modalbox.hide(box);
var fd = new FormData();
fd.append('file', file.files[0]);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/FileUpload/Convert', true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
alert('File successfully conveted to PDF');
}
};
xhr.send(fd);
}
In ch the drop down option gets saved.
I want to send ch value to the controller
Controller code:
public ActionResult Convert(HttpPostedFileBase file, FormCollection data)
{
string choice = data["choice"];
how can i send it?
You could add it to the FormData:
var fd = new FormData();
fd.append('file', file.files[0]);
fd.append('choice', ch.value);
and your controller action may now look like this:
public ActionResult Convert(HttpPostedFileBase file, string choice)
{
...
}

Web Server send data along with file

I'd like to serve an html page as well as some json to the client without a round-trip that can be processed on the client side. Is this possible? What's the best way of doing this? I've considered sending it in the header but it seems to be frowned upon by some. Any examples are greatly appreciated. Psuedo code:
main(){
...
app.addRequestHandler((req) => req.path == '/user', handler);
}
void handler(req, res) {
var file = new File(myHtmlFile);
res.headers.set(...); //add json here?
res.outputstream... //or here?
...
stream.pipe(res.outputStream);
}
In your html file you can put a tag to be replace before sending as response.
For instance, in your html file :
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<input type='hidden' id='datas' value="___JSON_DATAS___"/>
...
</body>
</html>
___JSON_DATAS___ will be replace in your server with something like :
void handler(req, res) {
var file = new File(myHtmlFile);
readStreamAsString(file.openInputStream()).then((fileContent) {
final content = fileContent
.replaceAll("___JSON_DATAS___", htmlEscape(jsonAsString));
res.outputStream.writeAsString(content);
res.outputStream.close();
});
}
String htmlEscape(String text) {
return text.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "&apos;");
}
Future<String> readStreamAsString(InputStream stream) {
final completer = new Completer();
final sb = new StringBuffer();
final sis = new StringInputStream(stream);
sis
..onData = () { sb.add(sis.read()); }
..onClosed = () { completer.complete(sb.toString()); }
..onError = (e) { completer.completeException(e); };
return completer.future;
}
Then, on client side :
import 'dart:html';
import 'dart:json';
main(){
final input = query('#datas') as InputElement;
final datas = JSON.parse(input.value);
//...
}

Google Dart Simple Contact form

I'm trying to make a contact form in Dart. So far I can understand the server needs to include something like the following:
server
app.addRequestHandler(
(req) => req.method == 'POST' && req.path == '/adduser',
(req, res) {
//process json data
};
}
);
And a form for the client:
<form method="post" action="/adduser">
<fieldset>
<legend>Add a user</legend>
<p><label>First name</label>
<input name="user[first_name]"/></p>
<p><label>Email</label>
<input name="user[email]"/></p>
<p class="actions"><input type="submit" value="Save"/></p>
</fieldset>
</form>
What needs to be done on the client side to get the json data to the server side?
Is json necessary to process the form or is there a better way?
You can submit your form to server directly. The content will be sent URL-encoded in the body of the post request. On server, you can decode datas with the query_string package available on pub.
Add query_string to your pubspec.yaml file:
dependencies:
query_string: ">=1.0.0 <2.0.0"
Your server code can looks like :
import 'dart:io';
import 'package:query_string/query_string.dart';
main() {
final server = new HttpServer();
server.listen('127.0.0.1', 8081);
server.addRequestHandler((req) => req.method.toUpperCase() == 'POST'
&& req.path == '/adduser', (request, response) {
readStreamAsString(request.inputStream).then((body) {
final params = QueryString.parse("?${body}");
print(params["user[first_name]"]);
print(params["user[email]"]);
response.statusCode = HttpStatus.CREATED;
response.contentLength = 0;
response.outputStream.close();
});
});
}
Future<String> readStreamAsString(InputStream stream) {
final completer = new Completer();
final sb = new StringBuffer();
final sis = new StringInputStream(stream);
sis
..onData = () { sb.add(sis.read()); }
..onClosed = () { completer.complete(sb.toString()); }
..onError = (e) { completer.completeException(e); };
return completer.future;
}

Resources