Phonegap Filetransfer Upload Issue with WCF OData - c#

I am trying to upload file using phonegap "FileTransfer". I am using .NET WCF OData for uploading the image.
The "upload" function not calling my API, and returns the below error message:
{"code":null,"source":null,"http_stats":null,"body":null}
my described code is as below:
navigator.camera.getPicture(function(imageURI){
var url = encodeURI("http://api.xyz.com/DataService/DataService.svc/UploadImage");
var params = new Object();
params.id= parseInt(1);
var options = new FileUploadOptions();
options.fileKey = "file";
options.fileName = imageURI.substr(imageURI.lastIndexOf('/') + 1);
options.mimeType = "image/jpeg";
options.params = params;
options.chunkedMode = true;
var ft = new FileTransfer();
ft.upload(imageURI, url, function (data) { alert(JSON.stringify(data)) }, function (data) { alert(JSON.stringify(data)) }, options);
}
and my WCF OData code is as below:
[WebInvoke]
public void UploadImage(int id)
{
// **what to write here???**
}
I also tried with following code but window.resolveLocalFileSystemURI function throws an Error calling method on NPObject error
navigator.camera.getPicture(function (imageURI) {
var _this = this;
var encodedURL = encodeURI("http://api.xyz.com/DataService/DataService.svc/UploadImage");
try {
this.op = new FileUploadOptions();
this.op.fileKey = "file";
this.op.fileName = imageURI.substr(imageURI.lastIndexOf('/') + 1);
this.op.mimeType = "image/jpeg";
this.op.chunkedMode = false;
this.op.headers = { Connection: "close" };
this.ft = new FileTransfer();
if (window.device != undefined && device.platform == "Android") {
window.resolveLocalFileSystemURI(imageURI, function (fileEntry) {
fileEntry.file(function (fileObj) {
var fileFullPath = fileObj.fullPath;
_this.op.fileName = fileFullPath.substr(fileFullPath.lastIndexOf('/') + 1);
_this.ft.upload(fileFullPath, encodedURL, function (data) { alert("Success: " + JSON.stringify(data)); }, function (data) { alert("Failour: " + JSON.stringify(data)); }, _this.op, true);
});
});
} else {
this.ft.upload(imageURI, encodedURL, function (data) { alert("Success: " + JSON.stringify(data)); }, function (data) { alert("Failour: " + JSON.stringify(data)); }, this.op, true);
}
} catch (_error) {
alert(_error);
}
},
function (message) { },
{
quality: 50,
destinationType: navigator.camera.DestinationType.FILE_URI,
sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY
});
}

Related

How to secure file download via controller action and ajax?

I have an application where I want users to be able to upload and download their own files. I implemented the upload and download however I am concerned with XSS vulnerability of the download action. I was only able to implement the file actually downloading using GET method, but I want to secure it (usually I use POST + antiforgery token). How can I do this?
This is my controller action:
public ActionResult DownloadFile(int clientFileId)
{
var clientId = GetClientId(clientFileId);
var client = _unitOfWork.Clients.GetById(clientId);
if (client == null)
return HttpNotFound();
var file = _unitOfWork.ClientFiles.GetById(clientFileId);
if (file == null)
return HttpNotFound();
var practiceId = _unitOfWork.Users.GetPracticeIdForUser(User.Identity.GetUserId());
if (!AuthorizationHelper.CheckBelongsToPractice(_unitOfWork.Clients, typeof(Client),
practiceId, client.Id, nameof(Client.Id), nameof(Client.PracticeId)))
{
return new HttpUnauthorizedResult();
}
var fileInfo = new FileInfo(file.FilePath);
var fileName = fileInfo.Name;
if (!fileInfo.Exists)
return HttpNotFound();
var path = Path.Combine(Server.MapPath("~/ClientFiles/" + clientId + "/"), fileName);
var contentType = MimeMapping.GetMimeMapping(path);
try
{
var contentDisposition = new System.Net.Mime.ContentDisposition
{
FileName = fileName,
Inline = false,
};
Response.AppendHeader("Content-Disposition", contentDisposition.ToString());
return File(path, contentType, fileName);
}
catch (Exception ex)
{
new ExceptionlessLogger(ex).Log();
return new HttpStatusCodeResult(500);
}
}
And my ajax call
$('#client-files-table').on('click', '.js-download', function () {
var link = $(this);
$.ajax({
url: '/clients/clientfiles/downloadfile?clientFileId=' + link.attr('data-clientfile-id'),
method: 'GET',
//data: {
// __RequestVerificationToken: getToken()
//},
success: function () {
window.location = '/clients/clientfiles/downloadfile?clientFileId=' + link.attr('data-clientfile-id'),
loadPartials();
},
error: function () {
toastr.error('Unable to download.');
}
});
});
I found the answer here: https://codepen.io/chrisdpratt/pen/RKxJNo
$('#client-files-table').on('click', '.js-download', function () {
var link = $(this);
$.ajax({
url: '/clients/clientfiles/downloadfile?clientFileId=' + link.attr('data-clientfile-id'),
method: 'POST',
data: {
__RequestVerificationToken: getToken()
},
xhrFields: {
responseType: 'blob'
},
success: function (data, status, xhr) {
var a = document.createElement('a');
var url = window.URL.createObjectURL(data);
a.href = url;
var header = xhr.getResponseHeader('Content-Disposition');
var filename = getFileNameByContentDisposition(header);
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
loadPartials();
},
error: function () {
toastr.error('Unable to download.');
}
});
});

Ajax Response Doesn't work from server side (iis)

I try to save a file (image) on C# MVC and JS with the following function js
function Add() {
var data = new FormData();
var files = $("#txtUploadFile").get(0).files;
var cod = document.getElementById('cod').value;
var mat = document.getElementById('mat').value;
var status = document.getElementById('status').value;
var plant = document.getElementById('plant').value;
if (files.length > 0) {
if (window.FormData !== undefined) {
var data = new FormData();
for (var x = 0; x < files.length; x++) {
data.append("file" + x, files[x]);
data.append("mat", mat);
data.append("status", status);
data.append("plant", plant);
data.append("code", cod);
}
$.ajax({
type: 'POST',
url: '/Pred/Admin/AddPred',
contentType: false,
processData: false,
data: data,
success: function (response) {
if(response.msg == 1)
{
refreshTable(response.data);
}
alert('Predio agregado.');
},
error: function (xhr, status, p3, p4) {
var err = "Error " + " " + status + " " + p3 + " " + p4;
if (xhr.responseText && xhr.responseText[0] == "{")
err = JSON.parse(xhr.responseText).Message;
}
});
}
}
}
and on the codebehind I used it
public ActionResult AddPred()
{
int isInsert=0;
string route = ConfigurationManager.AppSettings["MAPS_ROUTE"];
string[] status, plants, mats, codes;
int stat;
try
{
var requeststatus = Request.Params;
status = requeststatus.GetValues("status");
plants = requeststatus.GetValues("plant");
codes = requeststatus.GetValues("cod");
mats = requeststatus.GetValues("mat");
if (status[0] == "On")
stat= 1;
else
stat= 0;
string plant = plants[0];
string mat = mats[0];
string code = codes[0];
foreach (string file in Request.Files)
{
var fileContent = Request.Files[file];
if (fileContent != null && fileContent.ContentLength > 0)
{
var fileName = fileContent.FileName;
var path = Path.Combine(Server.MapPath(route), fileName);
path = Server.MapPath(route) + fileName;
var sqlpath = "." + route + "/" + fileName;
fileContent.SaveAs(path);
isInsert = ma.InsertPred(code, mat, stat, plant, sqlpath);
}
}
merge.preds = ma.GetPreds();
return Json(new { success = true, data = merge.preds, msg = isInsert }, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json("add failed");
}
}
But the server response ever is
POST myserver/Preds/Admin/AddPred 500 (Internal Server Error)
and I used console.log but I can't to get the error information, When used this code on local side, it's runs Okey, save the image and return model for refresh the front, but when put the aplication on the server, only return error, others funtions works (modal show, return model with json) but doesn't work save a image, I set permissions (write, load, modify) on the server folder,
someone give a idea for solves this problem, I don't know whats wrong
Try like this :
function getCities(id) {
$.ajax({
type: "POST",
url: "#Url.Action("Index", "Default")",
data: '{id: id }',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
//alert(response.responseData);
window.location = '/Default/YourView';//
},
error: function (response) {
alert("error!"); //
}
});
}
//In your controller
public JsonResult Index(string id)
{
merge.country= mp.Country();
merge.city= mp.City(id);
return Json("you can return an object or a string, what you want");
}

How can i get remote call on bootstrap twitter typeahead to work, by calling asp.net web method

I am trying to load my typeahead.js by using bloohound's remote function where i can call my Web Method. I have seen similar threads where a querystring is being used :
Integrating Typeahead.js with ASP.Net Webmethod
Typeahead.js and Bloodhound.js integration with C# WebForms WebMethod
http://yassershaikh.com/using-twitter-typeahead-js-with-asp-net-mvc-web-api/
And many more....
However, i cannot find an example where ajax is used to call the webmethod from typeahead.js.
So this is what i have currently and it works:
WebMethod
[WebMethod]
public static string GetEmployeeTypeahead()
{
JavaScriptSerializer jss = new JavaScriptSerializer();
jss.MaxJsonLength = 100000000;
string json;
using (var rep = new RBZPOS_CSHARPEntities())
{
var result = rep.Employees
.Where(x => x.EMPLOYEESTATE == 1)
.Select(x => new {
x.EMPLOYEEID,
x.FULLNAME,
x.MANNO,
x.NRC
}).ToList();
json = jss.Serialize(result);
}
return json;
}
The Client
function LoadEmployeeJSON() {
$.ajax({
type: "POST",
url: "/WebMethods/Test.aspx/GetEmployeeTypeahead",
data: "{}",
contentType: "application/json",
dataType: "json",
success: function (msg) {
empList = $.parseJSON(msg.d); //otherwise does not work
LoadEmployeeTypeahead();
},
error: function (msg) {
alert("error:" + JSON.stringify(msg));
}
});
}
function LoadEmployeeTypeahead() {
var empData = empList;
var fullname = new Bloodhound({
datumTokenizer: function (d) {
return Bloodhound.tokenizers.whitespace(d.FULLNAME)
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: empData,
limit: 10
});
fullname.initialize();
// Make the code less verbose by creating variables for the following
var fullnameTypeahead = $('#<%=txtFullName.ClientID %>.typeahead');
// Initialise typeahead for the employee name
fullnameTypeahead.typeahead({
highlight: true
}, {
name: 'FULLNAME',
displayKey: 'FULLNAME',
source: fullname.ttAdapter(),
templates: {
empty: [
'<div class="empty-message">',
'No match',
'</div>'
].join('\n'),
suggestion: function (data) {
return '<h6 class="">' + data.FULLNAME + "<span class='pull-right text-muted small'><em>" + data.NRC + "</em></span>" + '</h6>';
}
}
});
var fullnameSelectedHandler = function (eventObject, suggestionObject, suggestionDataset) {
/* See comment in previous method */
$('#<%=txtFullName.ClientID %>').val(suggestionObject.FULLNAME);
$('#<%=txtEmployeeID.ClientID %>').val(suggestionObject.EMPLOYEEID);
$('#<%=txtManNo.ClientID %>').val(suggestionObject.MANNO);
$('#<%=txtNRC.ClientID %>').val(suggestionObject.NRC);
};
// Associate the typeahead:selected event with the bespoke handler
fullnameTypeahead.on('typeahead:selected', fullnameSelectedHandler);
}
function clearAndReInitilize() {
$('.typeahead').typeahead('destroy');
$('.typeahead').val('');
}
So as you can see i am making a local call instead of remote.
How can i get the remote function to call my webthod and fill the typeahead without using any querystrings
Okay finally got it to work via an ashx generic handler. So instead of using a web method i used the following ashx handler:
public class Employess : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
jss.MaxJsonLength = Int32.MaxValue;
string json;
string prefixText = context.Request.QueryString["query"];
using (var rep = new RBZPOS_CSHARPEntities())
{
var result = rep.Employees
.Where(x => x.EMPLOYEESTATE == 1 && x.FULLNAME.Contains(prefixText.ToUpper()))
.Select(x => new
{
x.EMPLOYEEID,
x.FULLNAME,
x.MANNO,
x.NRC
}).ToArray();
json = jss.Serialize(result);
}
context.Response.ContentType = "text/javascript";
context.Response.Write(json);
}
public bool IsReusable
{
get
{
return false;
}
}
}
Below is the jquery and the ajax call to the ashx handler
$(document).ready(function () {
$(document).ajaxStart($.blockUI).ajaxStop($.unblockUI);
LoadEmployeeTypeahead();
// LoadEmployeeJSON();
});
function LoadEmployeeTypeahead() {
//var empData = empList;
var fullname = new Bloodhound({
remote: {
url: '/Employess.ashx?query=%QUERY',
wildcard: '%QUERY'
},
datumTokenizer: function (d) {
//var employees = $.parseJSON(msg.d);
return Bloodhound.tokenizers.whitespace(d.FULLNAME)
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
limit: 10
});
fullname.initialize();
// Make the code less verbose by creating variables for the following
var fullnameTypeahead = $('#<%=txtFullName.ClientID %>.typeahead');
// Initialise typeahead for the employee name
fullnameTypeahead.typeahead({
highlight: true
}, {
name: 'FULLNAME',
displayKey: 'FULLNAME',
source: fullname.ttAdapter(),
templates: {
empty: [
'<div class="empty-message">',
'No match',
'</div>'
].join('\n'),
suggestion: function (data) {
return '<h6 class="">' + data.FULLNAME + "<span class='pull-right text-muted small'><em>" + data.MANNO + "</em></span><span class='pull-right text-muted small'><em>" + data.NRC + "</em></span>" + '</h6>';
}
}
});
var fullnameSelectedHandler = function (eventObject, suggestionObject, suggestionDataset) {
/* See comment in previous method */
$('#<%=txtFullName.ClientID %>').val(suggestionObject.FULLNAME);
$('#<%=txtEmployeeID.ClientID %>').val(suggestionObject.EMPLOYEEID);
$('#<%=txtManNo.ClientID %>').val(suggestionObject.MANNO);
$('#<%=txtNRC.ClientID %>').val(suggestionObject.NRC);
};
// Associate the typeahead:selected event with the bespoke handler
fullnameTypeahead.on('typeahead:selected', fullnameSelectedHandler);
}

Why my code is repeated in async upload file web api

In upload async file :
for example if i uploading 3 file Debug.WriteLine(info.FullName); and _db.Files.Add(New FileDto{FileName=info.Name}); repeated 50 time.means 50 record insert in database.
Why and how to avoid it?
what is my problem?
public Task<IEnumerable<FileDesc>> Post()
{
string folderName = "uploads";
string PATH = HttpContext.Current.Server.MapPath("~/" + folderName);
string rootUrl = Request.RequestUri.AbsoluteUri.Replace(Request.RequestUri.AbsolutePath, String.Empty);
if (Request.Content.IsMimeMultipartContent())
{
var streamProvider = new CustomMultipartFormDataStreamProvider(PATH);
var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith<IEnumerable<FileDesc>>(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
var fileInfo = streamProvider.FileData.Select(i =>
{
var info = new FileInfo(i.LocalFileName);
Debug.WriteLine(info.FullName);//************Repeated******
_db.Files.Add(New FileDto{FileName=info.Name});//************Repeated******
return new FileDesc(info.Name, rootUrl + "/" + folderName + "/" + info.Name, info.Length / 1024);
});
return fileInfo;
});
return task;
}
else
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted"));
}
}
[Update]
CustomMultipartFormDataStreamProvider :
public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public CustomMultipartFormDataStreamProvider(string path)
: base(path)
{
}
public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
{
var name = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? headers.ContentDisposition.FileName : "NoName";
return name.Replace("\"", string.Empty);
}
}
[Update]
$('#fileupload').fileupload({
dataType: "json",
url: "/media/upload",
limitConcurrentUploads: 1,
sequentialUploads: true,
progressInterval: 100,
maxChunkSize: 10000,
add: function (e, data) {
$('#filelistholder').removeClass('hide');
data.context = $('<div />').text(data.files[0].name).appendTo('#filelistholder');
$('<div class="progress progress-striped active"><div style="width: 0%;" class="progress-bar progress-bar-warning"></div></div>').appendTo(data.context);
$('#btnUploadAll').click(function () {
data.submit();
});
},
done: function (e, data) {
data.context.text(data.files[0].name + '... Completed');
$('<div class="progress progress-striped active"><div style="width: 100%;" class="progress-bar progress-bar-success"></div></div>').appendTo(data.context);
},
progressall: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#overallbar').css('width', progress + '%');
},
progress: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
data.context.find('.progress-bar').css('width', progress + '%');
}
});
Your Debug.WriteLine is in the projection function of streamProvider.FileData.Select, so it is executed as many times as there are items in streamProvider.FileData.

Take Picture From Camera And Upload on Server Using WCF Service or HTTP Handler

I want to Store Camera Picture on server so I have user File Upload API of PhoneGap but there is no luck.
**My target platform is Windows Phone 7 and Android. On Windows Phone I am getting "Connection Error" and on Android I am getting File Not found error. I referred this link
Upload image from phonegap app to WCF service
**
Here is my code
$(document).on({
'pageinit': function (e) {
$(".divTakePhoto").on('click', function (event) {
event.preventDefault();
getPicture();
});
},
}, "#pgHome");
function getPicture(source) {
navigator.camera.getPicture(onCaptureSuccess, onCaptureFail,
{
quality: 10,
destinationType: navigator.camera.DestinationType.FILE_URI,
sourceType: navigator.camera.PictureSourceType.CAMERA
});
}
function onCaptureFail(message) {
alert('Failed because: ' + message);
};
function onCaptureSuccess(imageURI) {
var options = new FileUploadOptions();
options.chunkedMode = false;
options.fileKey = "recFile";
var imagefilename = imageURI;
options.fileName = imagefilename;
options.mimeType = "image/jpeg";
var ft = new FileTransfer();
ft.upload(imageURI, "http://myserver/MyAppService.svc/SaveImage", win, fail, options);
}
function resolveOnSuccess(entry) {
fileuri = entry.toURL();
//console.log(fileuri);
}
function fsFail(message) {
alert(JSON.stringify(message));
}
function win(r) {
alert("Sent = " + r.bytesSent);
}
function fail(error) {
switch (error.code) {
case FileTransferError.FILE_NOT_FOUND_ERR:
alert("Photo file not found");
break;
case FileTransferError.INVALID_URL_ERR:
alert("Bad Photo URL");
break;
case FileTransferError.CONNECTION_ERR:
alert("Connection error");
break;
}
alert("An error has occurred: Code = " + error.code);
}
Please help me if I am missing anything.
I also tried to post image through $.ajax()
here is the code for post image to http handler but it is showing parsing error.
function uploadPhoto(imageURI) {
$.ajax({
type: "POST",
url: "http://myserver/ImageHandler.ashx",
data: {
imgData: imageURI
},
success: function (data) {
alert(data);
var arr = new Array();
var responseData = data;
arr = (data.split("."));
if (arr[1].toString() != '') {
}
else
alert("Uploaded! " + data);
$.mobile.changePage("home.html");
var imageData = responseData.split("-");
},
error: function (request, error) {
alert("Error! " + error);
}
});
}

Categories

Resources