I am basically trying to upload a file using angular and a webmethod.
I took the code from this blog but it does not work. The request is successfull as seen from fiddler but the web method never gets invoked.
Am I doing something wrong?
Following is my code .
angular
.module('loader', ['ui.router', 'ui.bootstrap', 'ui.filters'])
.controller('loader-main', function($rootScope, $scope, WebServices) {
$scope.uploadNewFile = function() {
WebServices.uploadFile($scope.myfile);
}
}).factory('WebServices', function($rootScope, $http) {
return {
postFile: function(method, uploadData) {
var uploadUrl = "myASPXPAGE.aspx/" + method;
return $http.post(uploadUrl, uploadData, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
}).success(function(data) {
///Control reaches here but never hits the server method
});
},
uploadFile: function(filedata) {
var fd = new FormData();
fd.append('file', filedata);
return this.postFile("UploadFile", fd);
}
};
}).directive('fileModel', ['$parse',
function($parse) {
return {
restrict: 'A',
link: function($scope, element, attr) {
var model = $parse(attr.fileModel);
var modelSetter = model.assign;
element.bind('change', function() {
$scope.$apply(function() {
modelSetter($scope, element[0].files[0]);
});
});
}
}
}
]);
<div class="row">
<div class="col-xs-5">
<div class="col-xs-4">Browse to File:</div>
<div class="col-xs-1">
<input type="file" id="uploadFile" class="btn btn-default" file-model="myfile" />
<input type="button" class="btn btn-primary" value="Load File" data-ng-click="uploadNewFile()" />
</div>
</div>
</div>
And here is my WebMethod
[WebMethod]
public static string UploadFile()
{
System.Diagnostics.Debugger.Break();
return "Done";
}
Figured it out. You cannot have Content-Type as multipart/form-data in webmethods. Instead created a HttpHandler to upload the file and everything works just fine.
Related
I am trying to send a multipart form consist of text and file type using knockoutjs.
There is an error regarding data-bind file.
Here's my formView:
<div class="form-horizontal">
<div class="form-group">
<div class="col-md-12">
<label class="control-label">Supplier</label>
<input type="text" name="Supplier" id="Supplier" data-bind="value: Supplier" class="form-control col-md-8 form-control-sm" required />
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<label class="control-label">Picture</label>
<input type="file" name="fileInput" id="fileInput" data-bind="file: {data: fileInput, reader: someReader}" class="form-control" />
</div>
</div>
</div>
#section scripts {
<script src="~/Scripts/SDSScripts/RegisterSdsView.js"></script>
}
ViewModel:
function RegisterSdsView() {
var self = this;
self.Supplier = ko.observable();
self.fileInput = ko.observable();
someReader = new FileReader();
self.RegisterSds = function () {
if (self.errors().length > 0) {
self.errors.showAllMessages();
return;
}
var Supplier = self.Supplier();
var fileInput = self.fileInput();
$.ajax({
url: '/SdsView/RegisterSds',
cache: false,
type: 'POST',
data: {Supplier, fileInput},
success: function (data) {
//some code
},
error: function (data) {
//some code
}
});
}
}
ko.applyBindings(new RegisterSdsView());
Controller:
public ActionResult RegisterSds(string Supplier, HttpPostedFileBase fileInput)
{
var db = new SDSDatabaseEntities();
if (fileInput.ContentLength > 0)
{
string fileName = Path.GetFileNameWithoutExtension(fileInput.FileName);
string fileExtension = Path.GetExtension(fileInput.FileName);
string path = Path.Combine(Server.MapPath("~/UploadedFiles"), fileName);
fileInput.SaveAs(path);
var doc = new SDSDocument()
{
DocName = fileName,
DocType = fileExtension,
DocPath = path
};
db.SDSDocuments.Add(doc);
}
db.SaveChanges();
var result = new { status = "OK" };
return Json(result, JsonRequestBehavior.AllowGet);
}
The problem is the fileInput(viewModel) return null to my controller(HttpPostedFileBase fileInput).
Am I doing these the right way?
This is actually my very first C# .NET project. I can't seem to find a good example related to knockoutjs file data-bind. Basically how to POST Based64 to controller?
Here the api that I use https://github.com/TooManyBees/knockoutjs-file-binding
Well I solved it. I gonna update it here just in case. Basically I just have to POST Base64 string to controller via FormData. I don't know why my previous method cannot send large string value, maybe there are limitation on POST method or browser on how large you can send a data via AJAX.
Here is the reference https://stackoverflow.com/a/46864228/13955999
I have two reCaptcha V2 controls within two forms in one page, one is visible another is invisible. All is fine except the invisible one's data-callback callback - submitSendForm() did not get called. Once I removed the visible one, the invisible one starts working.
So the process is like once user completed the first visible challenge then the second form(within same page) will show with the invisible one, that's when the call back failed to be called.
It hasn't to be one visible and another invisible. But I found this to be easy when you want to have multiple controls.
Here is the code:
using (Html.BeginForm("Verify", "CertificateValidation", FormMethod.Post, new { id = "verifyForm" }))
{
<div class="form-group">
<div class="g-recaptcha" data-sitekey='site-key' data-callback="enableBtn"
style="transform: scale(0.66); transform-origin: 0 0;">
</div>
<div class="col-sm-3">
<button type="submit" id="verify" disabled>Verify</button>
</div>
</div>
}
using (Html.BeginForm("Send", "CertificateValidation", FormMethod.Post, new { id = "sendForm" }))
{
<div id='recaptcha1' class="g-recaptcha"
data-sitekey='site-key'
data-callback="submitSendForm"
data-size="invisible"></div>
<button type="submit">Send</button>
}
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script type="text/javascript">
function submitSendForm() {
console.log('captcha completed.');
$('#sendForm').submit();
}
$('#sendForm').submit(function (event) {
console.log('form submitted.');
if (!grecaptcha.getResponse()) {
console.log('captcha not yet completed.');
event.preventDefault(); //prevent form submit
grecaptcha.execute();
} else {
console.log('form really submitted.');
}
});
var enableBtn = function (g_recaptcha_response) {
$('#verify').prop('disabled', false);
};
$(document).ready(function () {
$('#verify').click(function () {
$captcha = $('#recaptcha');
response = grecaptcha.getResponse();
if (response.length === 0) {
return false;
} else {
return true;
}
});
});
</script>
I got it figured out somehow:
var CaptchaCallback = function () {
grecaptcha.render('RecaptchaField1', { 'sitekey': 'site-key', 'callback': 'enableBtn' });
window.recaptchaField2Id = grecaptcha.render('RecaptchaField2', { 'sitekey': 'site-key', 'callback': 'submitSendForm', 'size': 'invisible' });
};
function submitSendForm() {
$('#sendForm').submit();
}
$('#sendForm').submit(function (event) {
if (!grecaptcha.getResponse(window.recaptchaField2Id)) {
event.preventDefault();
grecaptcha.execute(window.recaptchaField2Id);
}
});
using (Html.BeginForm("Verify", "CertificateValidation", FormMethod.Post, new { id = "verifyForm" }))
{
<div class="form-group">
<div style="transform: scale(0.66); transform-origin: 0 0;" id="RecaptchaField1"></div>
<div class="col-sm-3">
<button type="submit" id="verify" disabled>Verify</button>
</div>
</div>
}
using (Html.BeginForm("Send", "CertificateValidation", FormMethod.Post, new { id = "sendForm" }))
{
<div id="RecaptchaField2"></div>
<button type="submit">Send</button>
}
This one worked for me, clean and easy.
Javascript
var reCaptcha1;
var reCaptcha2;
function LoadCaptcha() {
reCaptcha1 = grecaptcha.render('Element_ID1', {
'sitekey': 'your_site_key'
});
reCaptcha2 = grecaptcha.render('Element_ID2', {
'sitekey': 'your_site_key'
});
};
function CheckCaptcha1() {
var response = grecaptcha.getResponse(reCaptcha1);
if (response.length == 0) {
return false; //visitor didn't do the check
};
};
function CheckCaptcha2() {
var response = grecaptcha.getResponse(reCaptcha2);
if (response.length == 0) {
return false; //visitor didn't do the check
};
};
HTML
<head>
<script src="https://www.google.com/recaptcha/api.js?onload=LoadCaptcha&render=explicit" async defer></script>
</head>
<body>
<div id="Element_ID1"></div>
<div id="Element_ID1"></div>
</body>
In my meteor app I am uploading images and storing them in dropbox. It works fine when I am running the app in localhost. But as soon as I run the app after deploying it to meteor.com the upload fails to work.
This is my code in server.js
var createThumb = function(fileObj, readStream, writeStream) {
// Transform the image into a 10x10px thumbnail
gm(readStream, fileObj.name()).resize('10', '10').stream().pipe(writeStream);
};
var dropboxStore = new FS.Store.Dropbox("files", {
key: "",
secret: "",
token: "", // Don’t share your access token with anyone.
transformWrite: createThumb, //optional
})
Images = new FS.Collection("files", {
stores: [dropboxStore]
});
Images.allow({
'insert': function () {
// add custom authentication code here
return true;
}
});
Here is the link to meteor.com http://image_upload.meteor.com/.
I have tried changing dropbox to s3 but it still doesn't work. Could it be because it is hosted at meteor.com?
Looking forward for a solution.
Most likely it's because you're trying to use GraphicsMagick to resize the image in the transformWrite option, but meteor.com hosting servers do not have GraphicsMagick or ImageMagick installed.
https://github.com/CollectionFS/Meteor-CollectionFS/issues/299
You can use the meteor logs command to view the logs from your hosted meteor.com application to make sure that's the issue.
Edit
Here's some sample code for the jQuery cropper utility:
Template HTML:
<input type="file" style="visibility:hidden;width:1px" accept="image/gif, image/jpeg, image/png" class="profilePhotoFile">
<input type="button" id="btnEditPhoto" value="Edit Photo" class="btn btn-primary" style="width:160px"/>
<div class="modal fade" id="cropper-modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div id="cropper">
<img src="" alt="Picture">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" id="btnSavePhoto">Save</button>
<button class="btn btn-default" id="btnCancel">Cancel</button>
</div>
</div>
</div>
</div>
Template JS:
Template.myTemplate.events({
'click #btnEditPhoto': function(event, template) {
$('.profilePhotoFile').click();
},
'change .profilePhotoFile': function(event, template) {
if (!event.target.files || event.target.files.length === 0) {
return;
} else {
var $inputImage = $(event.target);
var URL = window.URL || window.webkitURL;
var file = event.target.files[0];
var blobURL = URL.createObjectURL(file);
$image = $('#cropper > img');
$('#cropper-modal').modal();
$('#cropper-modal').on('shown.bs.modal', function() {
$image.cropper({
aspectRatio: 1.0,
autoCropArea: 1.0
}).cropper('replace', blobURL);
$inputImage.val('');
}).on('hidden.bs.modal', function() {
$image.cropper('destroy');
URL.revokeObjectURL(blobURL); // Revoke url
});
}
},
'click #btnSavePhoto': function(event, template) {
$image = $('#cropper > img');
//Change the width and height to your desired size
var base64EncodedImage = $image.cropper('getCroppedCanvas', {width: 10, height: 10}).toDataURL('image/jpeg');
$('#cropper-modal').modal('hide');
var newImage = new FS.File(base64EncodedImage);
Images.insert(newImage, function(err, fileObj) {
if (err) {
console.log(err);
} else {
//do something after insert
}
});
},
'click #btnCancel': function(event, template) {
$('#cropper-modal').modal('hide');
}
});
I am trying to use Google Picker within a Meteor application. I am not an expert, I just followed the example on Google Picker API page https://developers.google.com/picker/docs/index but could not make it work.
Here is what I tried in the client side and of course I changed the devKey and Client ID:
// The Browser API key obtained from the Google Developers Console.
var developerKey = 'AIzaSyC9gfrgtnj6fd00hDau3B0LSTqajeDIyl0';
// The Client ID obtained from the Google Developers Console. Replace with your own Client ID.
var clientId = "582812345678-5t9joqkb5d1rfders25fhr5u6k28s9lc.apps.googleusercontent.com"
// Scope to use to access user's photos.
var scope = ['https://www.googleapis.com/auth/photos'];
var pickerApiLoaded = false;
var oauthToken;
Template.gPicker.helpers({
// Use the API Loader script to load google.picker and gapi.auth.
onApiLoad : function() {
gapi.load('auth', {'callback': onAuthApiLoad});
gapi.load('picker', {'callback': onPickerApiLoad});
},
onAuthApiLoad : function() {
window.gapi.auth.authorize(
{
'client_id': clientId,
'scope': scope,
'immediate': false
},
handleAuthResult);
},
onPickerApiLoad : function() {
pickerApiLoaded = true;
createPicker();
},
handleAuthResult : function(authResult) {
if (authResult && !authResult.error) {
oauthToken = authResult.access_token;
createPicker();
}
},
// Create and render a Picker object for picking user Photos.
createPicker : function() {
if (pickerApiLoaded && oauthToken) {
var picker = new google.picker.PickerBuilder().
addView(google.picker.ImageSearchView).
setOAuthToken(oauthToken).
setDeveloperKey(developerKey).
setCallback(pickerCallback).
build();
picker.setVisible(true);
}
},
// A simple callback implementation.
pickerCallback : function(data) {
var url = 'nothing';
if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
url = doc[google.picker.Document.URL];
}
var message = 'You picked: ' + url;
document.getElementById('result').innerHTML = message;
}
});
Then on the template:
<head>
<title>imagesearch</title>
</head>
<body>
{{> gPicker}}
<script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
<template name="gPicker">
<div class="col-lg-6">
<div class="input-group">
<input type="text" class="form-control recherche">
<span class="input-group-btn">
<button class="btn btn-default" type="button">Go!</button>
</span>
</div>
</div>
<div id="result"></div>
</template>
Can anyone help with a working example of recaptcha in meteor without using iframes?
I cannot make the recaptcha scripts run even when I try to run them from the client.js using jquery append.
After doing some investigations I found that I had to manually integrate the reCaptcha.
The client side code:
HTML:
<form id="mySecuredForm" novalidate>
<!-- labels and inputs here -->
<div class="row">
<div id="captcha-container">
<div id="rendered-captcha-container">loading...</div>
</div>
</div>
<div class="row">
<button type="submit" id="submit" class="submit-button">Submit</button>
</div>
</form>
JS
if (Meteor.isClient) {
Template.myTemplate.rendered = function() {
$.getScript('http://www.google.com/recaptcha/api/js/recaptcha_ajax.js', function() {
Recaptcha.create('add_your_public_key_here', 'rendered-captcha-container', {
theme: 'red',
callback: Recaptcha.focus_response_field
});
});
}
Template['myTemplate'].events({
'submit form#mySecuredForm': function(event) {
event.preventDefault();
event.stopPropagation();
var formData = {
captcha_challenge_id: Recaptcha.get_challenge(),
captcha_solution: Recaptcha.get_response()
//add the data from form inputs here
};
Meteor.call('submitMySecuredForm', formData, function(error, result) {
if (result.success) {
//set session vars, redirect, etc
} else {
Recaptcha.reload();
// alert error message according to received code
switch (result.error) {
case 'captcha_verification_failed':
alert('captcha solution is wrong!');
break;
case 'other_error_on_form_submit':
alert('other error');
break;
default:
alert('error');
}
}
});
}
Server side code
function verifyCaptcha(clientIP, data) {
var captcha_data = {
privatekey: 'add_private_key_here',
remoteip: clientIP
challenge: data.captcha_challenge_id,
response: data.captcha_solution
};
var serialized_captcha_data =
'privatekey=' + captcha_data.privatekey +
'&remoteip=' + captcha_data.remoteip +
'&challenge=' + captcha_data.challenge +
'&response=' + captcha_data.response;
var captchaVerificationResult = null;
var success, parts; // used to process response string
try {
captchaVerificationResult = HTTP.call("POST", "http://www.google.com/recaptcha/api/verify", {
content: serialized_captcha_data.toString('utf8'),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': serialized_captcha_data.length
}
});
} catch(e) {
return {
'success': false,
'error': 'google_service_not_accessible'
};
}
parts = captchaVerificationResult.content.split('\n');
success = parts[0];
if (success !== 'true') {
return {
'success': false,
'error': 'captcha_verification_failed'
};
}
return {
'success': true
};
}
Meteor.methods({
"submitMySecuredForm": function(data) {
//!add code here to separate captcha data from form data.
var verifyCaptchaResponse = verifyCaptcha(this.connection.clientAddress, data);
if (!verifyCaptchaResponse.success) {
console.log('Captcha check failed! Responding with: ', verifyCaptchaResponse);
return verifyCaptchaResponse;
}
console.log('Captcha verification passed!');
//!add code here to process form data
return {success: true};
});
There is also the possibility to listen to the post event on the server side. The http calls can be done synchronous as above or asynchronous with fibers/futures.
Server side http call to google API was inspired from:
https://github.com/mirhampt/node-recaptcha/blob/master/lib/recaptcha.js