Kendo UI Uploader Async Cross Site Scripting Issue with ASP.NET - c#

I have attempted to use the Kendo UI Uploader in async mode in an ASP.NET environment, using very similar code to the demo's on there site and am getting what appears to be a JQuery cross site scripting error on both IE8 and Chrome 30.0.1599.101 m
The following is the code being used:
index.chtml
<!DOCTYPE html>
<html>
<head>
<title></title>
<link href="css/kendostyles/kendo.common.min.css" rel="stylesheet" />
<link href="css/kendostyles/kendo.default.min.css" rel="stylesheet" />
<script src="scripts/kendojs/jquery.min.js"></script>
<script src="scripts/kendojs/kendo.all.min.js"></script>
</head>
<body>
<div style="width:45%">
<div style="width:45%">
<div class="demo-section">
<input name="files" id="files" type="file" />
</div>
</div>
<script>
$(document).ready(function () {
$("#files").kendoUpload({
async: {
saveUrl: "save",
removeUrl: "remove",
autoUpload: true
}
});
});
</script>
</div>
</body>
</html>
I have extremely simple upload code that is not even being hit, but i will provide it for completeness:
public ActionResult Save(IEnumerable<HttpPostedFileBase> files)
{
// The Name of the Upload component is "files"
if (files != null)
{
foreach (var file in files)
{
// Some browsers send file names with full path.
// We are only interested in the file name.
var fileName = Path.GetFileName(file.FileName);
var physicalPath = Path.Combine(Server.MapPath("~/Uploads"), fileName);
// The files are not actually saved in this demo
// file.SaveAs(physicalPath);
}
}
// Return an empty string to signify success
return View();
}
Now upon selecting a file to be uploaded i receive the following javascript pop up message:
Error! Upload failed.Unexpected server response - see console.
Upon viewing the console i get this:
Server response: Error trying to get server response: SecurityError: Blocked a frame with origin "http://localhost:21739" from accessing a frame with origin "null". The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "data". Protocols must match.
in an attempt to resolve the issue after searching around for like issues i have tried bypassing the issue with changing the global.asax file
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
}
But that had no effect.
What is the way to get the Async Kendo File Upload working when presented with this sort of error, i have been unable to find anyone suffering from the same situation?

A couple of things:
1) chrome is explicit about XSS problems. Unless chrome console says cross site scripting error, then I don't think that's your issue.
2) Add yourself a call back for when it errors out.
$("#files").kendoUpload({
async: {
saveUrl: "save",
removeUrl: "remove",
autoUpload: true
},
error: onError
});
function onError(e){
alert("Failed to upload " + e.files.length + " files " + e.XMLHttpRequest.status + " " + e.XMLHttpRequest.responseText);
}
This will give you the response from the server.
3) Not sure if you are using Asp.net MVC or Web Api controllers (looks like ASP.Net MVC), but (maybe I'm wrong) it seems your save property needs the controller or route details.
$("#files").kendoUpload({
async: {
saveUrl: "MyControllerName/save", (or api/controller) ( or #Url.Action("Save", "ControllerName")
removeUrl: "remove",
autoUpload: true
}
});
4) returning KendoUI upload isn't going to like the return type ActionResult It requires a JsonResult return type. correction : Not 100% sure on this. Just be careful of how the return data is structured. If it's a string with well-formed HTML, the control will bark

Related

Return PDF file to user after ajax call to controller

I have a custom button on my Kendo Grid "Export to PDF". On click of this button, I call a service which generates a PDF file.I want to be able to display this PDF file on click of the "Export to PDF" button. I have it working to the point where it calls the service and I save the PDF locally on my machine as of now. How can I return this file to the View so that its either displayed on a new tab or maybe just a dialog which asks the user to open and save the save.
The following is the button click method which make the call to the controller:
<script>
function ExportDocGen_Click() {
var grid = $("#companyMasterRateSheets").data("kendoGrid");
var selectedItem = grid.dataItem(grid.select());
var orderQuoteId = selectedItem.QuoteID;
$.ajax({
url: '#Url.Action("GenerateRateSheetPDF", "AccountDetail")',
type: 'GET',
dataType: 'string',
cache: false,
data: { 'orderQuoteId': orderQuoteId },
success: function (color) {
return color;
},
error: function () {
alert('Error occured');
}
})
}
</script>
The controller is as follows:
[HttpGet]
public string GenerateRateSheetPDF(string orderQuoteId)
{
byte[] pdfData = ServiceManager.BuildPDF(Convert.ToInt32(orderQuoteId));
if (pdfData != null)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, pdfData);
System.IO.File.WriteAllBytes("hello.pdf", pdfData);
}
return ("hi");
}
I am returning string as of now since I am not sure what should the return type will be. Thanks for the help.
Because theres no people answer/comment this question yet. I think i need to give you help to do this thing generally (all language)
I dont know about .net and kendo but i will give you live demo and simple explaination. My code written in PHP but i will try to explain this generally, because this is the common question for any web developer
There is two way to doing this:
Save file to storage then give user the produced link
Ajax
$.ajax({
url: '/generatePDF',
success: function(d){
document.location = d;
}
})
controller (server side)
var pdf = createPDF();
saveToServer(pdf, 'path/filename.pdf');
this will give user pdf real path. (i think you dont want this in your case)
create file on the fly
Html
description
controller (server side)
var pdf = createPDF();
addHeader('Content-Disposition: attachment or inline');
printToScreen(pdf);
pdf choice:
replace active tab
open new tab
open new window
embed
force download (client storage)
save locally (server storage)
1. Replace Active Tab
Basic HTML: description
Javascript /jquery window.open(url, '_self'); 2nd param must be _self or _parent
Requirement: Content-Disposition is not attachment
2. Open New Tab
Basic HTML: description depend on user preference setting
Javascript /jquery window.open(url, '_blank'); without 3rd parameter
Requirement: Content-Disposition is not attachment
3. Open New Window
Basic HTML: description depend on user preference setting
Javascript /jquery window.open(url, '_blank', 'width=200'); with 3rd parameter
Requirement: Content-Disposition is not attachment
4. Embed
Basic HTML: <embed src="url"></embed>
javascript/jquery: $(selector).html('<embed src="url"></embed>');
Requirement: no matter Content-Disposition is attachment or not, browser always try to display it
5. Force Download (client storage)
Basic HTML: `
Javascript /jquery: document.location = url;
Requirement: Content-Disposition is must be attachment
6. Save locally (server storage)
I will not explain this because:
- you already doing this
- And every language have different syntax
Example Implementation
index.html (html + js)
<!--
basic html: depend on user browser preference setting to open as new window or new tab
-->
<button id="newtab1">new tab/new window: basic html</button>
<!--
force to open new tab
case: without ajax
-->
<button id="newtab2">new tab: jquery without ajax</button>
<!--
force to open new tab
case: with ajax
hint:
* window.open() outside ajax will NOT BLOCKED
* window.open() inside ajax will BLOCKED
* so we need to hack this
* 1st: prepare/declare new var to store blank window
* 2nd: change location.href to execute it inside ajax
-->
<button id="newtab3">new tab: jquery with ajax</button>
<!--
force to open new window
case: without ajax
-->
<button id="newwindow1">new window: jquery without ajax</button>
<!--
force to open new window
case: with ajax
-->
<button id="newwindow2">new window: jquery with ajax</button>
<!--
embed
-->
<button id="embed">embed</button>
<!--
the most easy way
force download using HTML5 anchor download attribute
maybe not work for old browser
hint:
- no download attribute: display pdf
- download attribute exists, but content-disposition header is not set as attachment: display pdf
- download attribute exists, but content-disposition header is set as attachment: download pdf
-->
<button id="forcedownload1">force download using anchor download attribute (fail)</button>
<button id="forcedownload1">force download using anchor download attribute (correct)</button>
<!--
force download using ajax
i think this work in old browser too, since jquery take care of them
-->
<button id="forcedownload2">force download 2 using ajax/jquery</button>
<hr>
<div id="preview-embed"></div>
<script src="jquery.min.js"></script>
<script>
$(function(){
/*
* you need to read window.open() first: https://www.w3schools.com/jsref/met_win_open.asp to understand the basic
* hint:
* window.open() recieve 4 parameter
* if we not set 3rd parameter: will force open new tab
* if we set 3rd parameter: will force open new window
*/
$('#newtab2').click(function(){
/*
* no matter content-disposition is attachment or not, it always display in browser
*/
window.open('http://creativecoder.xyz/stackoverflow/pdf-choice/createpdf.php?filename=dummy.pdf');
});
$('#newtab3').click(function(){
var newWindow = window.open("","window name");
$.ajax({
url: 'http://creativecoder.xyz/stackoverflow/pdf-choice/givemethelink.php',
success: function(d){
newWindow.location.href = d;
},
error: function(d){
alert('error');
}
});
});
$('#newwindow1').click(function(){
window.open('http://creativecoder.xyz/stackoverflow/pdf-choice/createpdf.php?filename=dummy.pdf','window name', 'width=200,height=100');
});
$('#newwindow2').click(function(){
var newWindow = window.open("","window name", 'width=200,height=100');
$.ajax({
url: 'http://creativecoder.xyz/stackoverflow/pdf-choice/givemethelink.php',
success: function(d){
newWindow.location.href = d;
},
error: function(d){
alert('error');
}
});
});
$('#embed').click(function(){
$('#preview-embed').html('<embed src="http://creativecoder.xyz/stackoverflow/pdf-choice/createpdf.php?file=dummy.pdf"></embed>');
});
$('#forcedownload2').click(function(){
$.ajax({
/*
* we need to get file with header attachment
* if our file is dont have Content-Disposition: attachment , this ajax will display pdf only
* so we need to set request parameter `force=1`
*/
url: 'http://creativecoder.xyz/stackoverflow/pdf-choice/givemethelink.php?force=1', //correct
//url: 'http://creativecoder.xyz/stackoverflow/pdf-choice/givemethelink.php', //fail
success: function(d){
document.location = d;
},
error: function(d){
alert('error');
}
});
});
});
</script>
server scripting
server script example is written in PHP, please find the match syntax using your own language.
here i will implement method 2 only. i have so much different case. But i will choose the case which we have 2 script: 1. for give the link 2. generate pdf
givemethelink.php (only give url path)
<?php
if(isset($_GET['force']) && $_GET['force'] ==1){ //if request GET parameter force exist and the value is 1
echo 'http://creativecoder.xyz/stackoverflow/pdf-choice/createpdf.php?filename=dummy.pdf&force=1';
}else{
echo 'http://creativecoder.xyz/stackoverflow/pdf-choice/createpdf.php?filename=dummy.pdf';
}
createpdf.php (generate pdf on the fly /method 2)
<?php
/*
* generate pdf on the fly here
* but here, i only use file_get_contents() to download existing pdf binary
* and then simply display it to the screen using echo
* because it can difficult to you to understand, if i give you real php generate pdf script
*/
$source = file_get_contents('dummy.pdf'); //download existing pdf. this line should be pdf generate script
/*
* set header. this is the key
* the main header requirement is Content-Disposition
* you still can set any other header which is optional
*/
header("Content-type: application/pdf"); //tell browser: this is pdf file (optional header example)
/*
* if is request GET force exists and the value is 1 : force download
* else display to the browser
*/
if(isset($_GET['force']) && $_GET['force'] ==1){
header("Content-Disposition: attachment; filename=newname.pdf"); //tell browser: download this
}else{
header("Content-Disposition: inline; filename=newname.pdf"); //tell browser: display this file in browser
}
echo $source; //print pdf source to screen
force=1 => give attachment header
else => give inline header
Here the live demo: http://creativecoder.xyz/stackoverflow/pdf-choice/index.html
Conclusion:
Create script which genereate pdf on the fly not the real/direct pdf path
set header content-disposition: attachment or not, each have the different behaviour
bonus example: try run this code
test.html
display 1
download 1
<hr>
display 2
download 2

Uploading certain file types to server through Dropzone.js

I'm trying to upload Microsoft Access-files to my webserver, using dropzone.js. Most files seem to upload fine: My action is called, and the files end up in the right folder. But if I try to send for example .mdb (MS Access) or .pdf files, the action isn't even called, and dropzone reports that server responded with 0 code.
I do not use any acceptedFiles or acceptedMimeTypes options in dropzone, and as far as I know, leaving them out should make it accept any filetypes. Also, if I restrict a file type, it does give me a proper message that the file type is not allowed.
HTML:
<div id="dropzone">
<form action="/Synchronizations/Upload" method="post"
enctype="multipart/form-data" class="dropzone"
id="myAwesomeDropzone">
</form>
</div>
Javascript looks like:
<link href="/Content/css/dropzone.css" rel="stylesheet" type="text/css" />
<script src="/Scripts/dropzone.js"></script>
<script>
Dropzone.options.myAwesomeDropzone = {
paramName: "file",
maxFilesize: 200
};
</script>
The action looks like:
[HttpPost]
public void Upload(IEnumerable<HttpPostedFileBase> file)
{
foreach (var f in file)
{
var fileName = Path.GetFileName(f.FileName);
var path = Path.Combine(Server.MapPath("~/Uploads/"), fileName);
f.SaveAs(path);
}
}
Any ideas?
Are you hitting a file size limitation? Perhaps look at this: http://blogs.telerik.com/aspnet-ajax/posts/13-07-15/upload-large-files-asp-net-radasyncupload

How to Redirect to external url from controller?

ASP.NET MVC 4 Project
How to Redirect to external url from HTTP-->HTTPS from controller?
I can't just type:
var url = #"https://www.someurl.com"
return Redirect(url);
it doesn't work.
Also I've tried this:
var uri = new UriBuilder(url)
{
Scheme = Uri.UriSchemeHttps
};
return Redirect(uri.ToString());
Well I stumbled on the same problem: I have an MVC website running under https and I have some situations where I need to redirect to some external url which I recieve as a parameter and when this url is an http url - say http://www.somethingontheweb.com - the straightforward
return Redirect("http://www.somethingontheweb.com");
actually does not work because after all it looks like this redirect to https://www.somethingontheweb.com which does not exist at all usually.
Still don't know why it works like this but I've found this work around: I've resorted to
meta refresh
So I have a page: ~/Views/Shared/DoRedirect.cshtml and here is its code:
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="0; url=#ViewBag.RedirectUrl" />
<title>redirecting</title>
</head>
<body>
<p>redirecting...</p>
</body>
</html>
and then my Controller code is just
ViewBag.RedirectUrl = url;
return View("DoRedirect");
You can mark your action with RequireHttps attribute. And your link will be automatic redirected to https
public class AccountController:Controller
{
[RequireHttps]
public ActionResult Login()
{
...
}
}
You can redirect to this action from your code - RedirectToAction.
Moreover you can check next thread for some extra idea - Redirect HTTP to HTTPS.
I see a problem now: I used
return Redirect(url);
but it was an action called from Ajax (my mistake not to remember it) so the correct solution was using:
return JavaScript("window.location = '" + url + "'");

pattern for sending server side events to a webpage

I am wondering if there are any design patterns that allow server side events to be passed to a website?
The best I can think of is having some state on the server that is updated when the event is triggered, then maybe call back to the server via ajax every so often to check the state, and return what I need. Is this suitable? Is there a better way of doing this?
My application is written in ASP.NET MVC4.
There are a couple of ways of handling this depending on how you would like to tackle it and what technologies you would like to introduce to your stack.
Firstly, a periodic ajax call to a controller method on your server that will report the current state of the server is perfectly fine, for example: If a long running task is started on your server, returning some kind of indication of its progress via a controller method and polling that method periodically is perfectly reasonable.
The other method is to use a technology called SignalR, which essentially allows your server to call javascript functions on your client, I would certainly recommend looking into it.
Small example:
Server:
public class Chat : Hub
{
public void Send(string message)
{
// Call the addMessage method on all clients
Clients.All.addMessage(message);
}
}
Client:
<script src="http://code.jquery.com/jquery-1.8.2.min.js" type="text/javascript"></script>
<script src="Scripts/jquery.signalR-1.0.0-alpha2.min.js" type="text/javascript"></script>
<!-- If this is an MVC project then use the following -->
<!-- <script src="~/signalr/hubs" type="text/javascript"></script> -->
<script src="/signalr/hubs" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
// Proxy created on the fly
var chat = $.connection.chat;
// Declare a function on the chat hub so the server can invoke it
chat.client.addMessage = function (message) {
$('#messages').append('<li>' + message + '</li>');
};
$("#broadcast").click(function () {
// Call the chat method on the server
chat.server.send($('#msg').val());
});
// Start the connection
$.connection.hub.start();
});
</script>
<div>
<input type="text" id="msg" />
<input type="button" id="broadcast" value="broadcast" />
<ul id="messages">
</ul>
</div>
The above example was taken from here:
https://github.com/SignalR/SignalR/wiki/QuickStart-Hubs
The SignalR website can be found here:
http://signalr.net/
I really love SignalR... it will probably provide the best experience for both you the programmer and the user too.
Hope this helps.
Sounds like you should be looking at the SignalR Project. This allows bi directional server communication.
You can wait for server event using long polling/comet it mean that you should send ajax request to server and ajax request not executed at once, request will wait for server event until timeout expired.
Alternatively you can to listening server's events using ajax call server events like this, without signalR framework, for example:
[SessionState(SessionStateBehavior.ReadOnly)]
public class HomeController : Controller
{
static readonly ManualResetEvent Starter = new ManualResetEvent(false);
public ActionResult Index()
{
return View();
}
public String RiseServerEvent()
{
Starter.Set();
return "";
}
public async Task<String> WaitForServerEvent()
{
string contents = null;
var result = Task.Factory.StartNew(() =>
{
var reg = ThreadPool.RegisterWaitForSingleObject
(Starter, (state, #out) =>
{
contents = DateTime.Now.TimeOfDay.ToString();
}, "Some Data", -1, true);
Starter.WaitOne(10000);
contents = DateTime.Now.TimeOfDay.ToString();
});
await result;
return contents;
}
}

How to update Model from partial after ajax file upload?

So I have ajax file upload partial (using Jquery Form plugin), it's working perfectly, but I don't know to update model value after file uploading
<div>
#Html.Partial("PhotoUpload", Model.Place)
</div>
Here I'm calling partial and giving to it part of a model.
#model PlaceMap.DAL.Entities.Place
#using (Html.BeginForm("PhotoUpload", "Place", FormMethod.Post, new { #id = "photoUpload", enctype = "multipart/form-data" }))
{
{
#Html.ValidationSummary(true, "Image upload was unsuccessful")
#Html.HiddenFor(m => m.Photo)
<input type="file" id="file" name="file"/>
<input type="submit" id="sbm" />
}
}
This is view code of partial, accepting model and form for uploading
var options = {
url: "/Place/PhotoUpload",
dataType: "json",
clearForm: true,
resetForm: true,
success: showResponse
};
function showResponse(responseText, statusText, xhr, $form)
{
$('#photo').append('<img src="/Images/Places/' + responseText.Photo + '" />');
}
$('#photoUpload').submit(function ()
{
$('#photoUpload').ajaxSubmit(options);
return false;
});
Javascript code for plugin
[Authorize]
[HttpPost]
public ActionResult PhotoUpload(string Photo, HttpPostedFileBase file)
{
try
{
using (var ms = new MemoryStream())
{
//some logic here
return Json(new { Photo = filename });
}
}
catch (ArgumentException)
{
}
return PartialView();
}
Controller action code. It's returning file name, it's going to js function "showResponse" and appending image to div. It's all work perfectly, but I have to write file name to #Model.Photo of this partial and I don't know how to do it. Any suggestions?
One possibility is to use text/plain from the server:
return Json(new { Photo = filename }, "text/plain");
and on the client manually parse:
function showResponse(responseText, statusText, xhr, $form) {
var data = $.parseJSON(responseText);
$('#photo').append('<img src="/Images/Places/' + data.Photo + '" />');
}
Obviously you lust remove the dataType: 'json' option for this to work.
Another possibility is to follow what's explained in the documentation and write a custom action result which will wrap your JSON response with the <textarea> tags:
Browsers that support the XMLHttpRequest Level 2 will be able to
upload files seamlessly and even get progress updates as the upload
proceeds. For older browsers, a fallback technology is used which
involves iframes since it is not possible to upload files using the
level 1 implmenentation of the XMLHttpRequest object. This is a common
fallback technique, but it has inherent limitations. The iframe
element is used as the target of the form's submit operation which
means that the server response is written to the iframe. This is fine
if the response type is HTML or XML, but doesn't work as well if the
response type is script or JSON, both of which often contain
characters that need to be repesented using entity references when
found in HTML markup.
To account for the challenges of script and JSON responses when using
the iframe mode, the Form Plugin allows these responses to be embedded
in a textarea element and it is recommended that you do so for these
response types when used in conjuction with file uploads and older
browsers. Please note, however, that if there is no file input in the
form then the request uses normal XHR to submit the form (not an
iframe). This puts the burden on your server code to know when to use
a textarea and when not to. If you like, you can use the iframe option
of the plugin to force it to always use an iframe mode and then your
server can always embed the response in a textarea. But the
recommended solution is to test for the 'X-Requested-With' request
header. If the value of that header is 'XMLHttpRequest' then you know
that the form was posted via ajax.

Categories