Google Dart Simple Contact form - dart

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;
}

Related

How to websocket in grails5

I want a grails application in which server sends some message at a fixed interval.
I have tried using spring-websocket plugin in grails, server and client are able to connect but that doesn't fullfill my requirement. i.e., I want, server sends some message at a fixed interval.
This is the server-side code :
package test
import org.springframework.messaging.handler.annotation.MessageMapping
import org.springframework.messaging.handler.annotation.SendTo
class ExampleController {
def index() { }
// server
#MessageMapping("/hello")
#SendTo("/topic/hello")
protected String hello(String world) {
List<String> list = new ArrayList<>();
BufferedReader file = new BufferedReader(new FileReader("src/main/resources/dummyLog.txt"));
file.eachLine {line ->
list.add(line)
}
int idx = (int)(Math.random() * list.size());
println idx;
return list.get(idx);
}
}
And this is the client-side code :
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', () => {
var socket = new SockJS("${createLink(uri: '/stomp')}");
var client = webstomp.over(socket);
client.connect({}, function() {
client.subscribe("/topic/hello", (message) => {
document.getElementById('helloDiv').append(message.body);
});
});
document.getElementById('helloButton').addEventListener('click', () => {
client.send("/app/hello", JSON.stringify("world"));
});
});
</script>
Thanks.

Error uploading file in Dart to Redstone Server

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

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.

How do I parse a form submission with Dart?

I wrote an HTTP server with Dart, and now I want to parse form submits. Specifically, I want to handle x-url-form-encoded form submit from HTML forms. How can I do this with the dart:io library?
Use the HttpBodyHandler class to read in the body of an HTTP request and turn it into something useful. In the case of a form submit, you can convert it to a Map.
import 'dart:io';
main() {
HttpServer.bind('0.0.0.0', 8888).then((HttpServer server) {
server.listen((HttpRequest req) {
if (req.uri.path == '/submit' && req.method == 'POST') {
print('received submit');
HttpBodyHandler.processRequest(req).then((HttpBody body) {
print(body.body.runtimeType); // Map
req.response.headers.add('Access-Control-Allow-Origin', '*');
req.response.headers.add('Content-Type', 'text/plain');
req.response.statusCode = 201;
req.response.write(body.body.toString());
req.response.close();
})
.catchError((e) => print('Error parsing body: $e'));
}
});
});
}

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);
//...
}

Resources