Is response to Ajax call different from that of to full postback - asp.net

When I try the following code with a postback the file download takes place normally:
FileInfo file = new FileInfo("C:\\a.txt");
Response.ClearContent();
Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
Response.AddHeader("Content-Length", file.Length.ToString());
Response.ContentType = "text/plain";
Response.TransmitFile(file.FullName);
Response.End();
However if I put the above code inside a public static web method and call it with AJAX I get error, like "Process was being aborted".(Of course to get the current response I write HttpContext.Current.Response) This makes me think that the nature of the two responses are different. My question is if they are different, then what exactly is/are different? Is there a way to achieve the same thing with AJAX?

The browser isn't going to receive the file via an XHR (Ajax) call. You will want to return the file location and then send the browser to that file via window.location or window.open.
Edit: Here's a Web Forms sample. My Web Forms skills are a little rusty since I've been using MVC now; the syntax is off the top of my head so you might need to fix it up a little.
ASPX Page
<div id="whateverIsContainingYourDialog">
<form id="mikeJMIsAwesome" runat="server">
<asp:TextBox id="firstName" runat="server" />
<asp:TextBox id="lastName" runat="server" />
<asp:Button id="submit" runat="server" />
</form>
</div>
Server Side Code
protected void submit_OnClick(object sender, EventArgs e) {
//Your logic for creating the file and the code you originally posted for serving the file.
}

What Ek0nomik said, file downloads are handled by the browser and cannot be handled through Javascript. The responses are both identical they are are both just http responses - you can verify this with fiddler or another tool (http://www.fiddler2.com/fiddler2/).
Essentially you ajax method will not be able to handle receiving a file and will certainly not have the permissions to assemble it and store it on you hard drive.
You can 'fake' a user clicking on a link using some Javascript.
Please check this similar question for an answer. I've pasted the answer from it below.
starting file download with JavaScript
We do it that way: First add this script.
<script type="text/javascript">
function populateIframe(id,path)
{
var ifrm = document.getElementById(id);
ifrm.src = "download.php?path="+path;
}
</script>
Place this where you want the download button(here we use just a link):
<iframe id="frame1" style="display:none"></iframe>
download
The file 'download.php' (needs to be put on your server) simply contains:
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
?>
So when you click the link, the hidden iframe then gets/opens the sourcefile 'download.php'. With the path as get parameter. We think this is the best solution!

Related

Changing client side components' properties while server side execution happening in asp.net

I have a <asp:Button /> which is used to export some a DataTable into Excel. I need to display a progress image while the DataTable is being generated. Below is my try for this but still stuck. May be I haven't understand the life cycle here. Appreciate any help.
ASPX
<asp:Button ID="ExportResults" runat="server" UseSubmitBehavior="false" Text="Export Selected" OnClientClick="showWaitingForExport();" OnClick="ExportResults_Click"/>
JavaScript
function showWaitingForExport() {
$("#progressbar").progressbar({ value: false });}
Code Behind
protected void ExportResults_Click(object sender, EventArgs e)
{
DataTable resultDT = GenerateDataTable(); //This is the time taking function and after this I need to hide my progressbar while response still not get end
ScriptManager.RegisterStartupScript(this, this.GetType(), "stopprogress", "$('#progressbar').progressbar('destroy');", true);
string filename = "Search_Results.xlsx";
workbook.AddWorksheet(resultDT, "Search Results");
workbook.SaveAs(Server.MapPath("~/Temp/" + filename));
Response.ContentType = "application/vnd.ms-excel";
Response.AppendHeader("Content-Disposition", "attachment; filename=" + filename + "");
Response.TransmitFile(Server.MapPath("~/Temp/" + filename));
Response.End();
}
Unless I misunderstood the question, check out this link - it's a fairly common thing that developers need to do: http://www.dotnetcurry.com/showarticle.aspx?ID=227
OnClientClick is called when you click the button, but then the request goes to the server (OnClick="ExportResults_Click") and the browser/client will show the normal loading page (usually a blank white page). You should be able to use an UpdatePanel with one of the strategies described in the link to show an update panel progress bar. The only way around this (that I'm aware of) is to use an async postback so the page is still displayed while the server is processing.
Does this make sense? Does the article help? I can go into more detail or show an example if necessary. I am not at a computer with Visual Studio to throw together an example, but I can post something tomorrow if no one else has answered.

ASPxUploadControl getting file size

Is there a correct way to getting the file size when uploading an image with ASPxUploadControl? When the file is uploaded I would like to show the file size. So far I've not found out any sample code on how to do it via Google.
My current code:
VB.NET
<dxuc:ASPxUploadControl ID="ASPxUploadControl1" runat="server" ShowProgressPanel="True"
ClientInstanceName="CompanyLogoUpload" FileUploadMode="OnPageLoad" ValidationSettings-GeneralErrorText="Upload Failed">
<ClientSideEvents TextChanged="HandleFileInputTextChanged" FileUploadComplete="HandleFileUploadComplete" />
</dxuc:ASPxUploadControl>
ASP.NET
function HandleFileUploadComplete(e, s)
{
var imgSrc = $("img[id$=CompanyLogoImage]").attr("src");
$("img[id$=CompanyLogoImage]").attr("src", imgSrc + "1");
}
function HandleFileInputTextChanged(e, s) {
$("input[id$=UseCompanyLogoCheckBox]").attr("checked", true);
$("#ChangeLogoContainer").removeClass("overlay");
CompanyLogoUpload.Upload();
}
Reference
It is not possible to get the File Size due to File Security. You can do it in PHP easily but not in this tag.
It can be checked only at server side Code Behind code.
It is possible to perform the client-side MaxFileSize validation when using the “Advanced Upload Mode” only:
Advanced Upload Mode > Client-Side Validation
This blog post shows how to wire up the client side events to show the thumbnail of the uploaded image.
<dxuc:ASPxUploadControl ID="ASPxUploadControl1" runat="server"
ClientInstanceName="uploader"
onfileuploadcomplete="ASPxUploadControl1_FileUploadComplete">
<ClientSideEvents FileUploadComplete="function(s, e) {
debugger;
_aspxGetElementById('PreviewImage').src = e.callbackData;
}" />
</dxuc:ASPxUploadControl>

problem in sending document when I click cancel

I have a link in aspx page and when i click on it,it shows a popup: open,save,cancel
but when i click cancel on that aspx page no other link works on that page.
code so far:
protected void method1()
{
byte[] byterendered = _Filename.OpenBinary();
Response.Clear();
Response.ClearHeaders();
Response.ClearContent();
Response.ContentType = "image/jpeg";
Response.AddHeader("Content-Disposition", "attachment;filename=abc.jpg");
Response.CacheControl = "Public";
Response.BinaryWrite(byterendered);
Response.End();
}
aspx code
<asp:Linkbutton id="link1" runat="server" onClick="method1" Text="LinkA"/>
<asp:Linkbutton id="link2" runat="server" onClick="method2" Text="LinkB" />
As the comments to your question have indicated, the reason is because your Response is being ended after the file dialog shows up. Once the response ends, any other actions on your page will not be registered. I ran into this myself while implementing a download function for my SharePoint app.
Basically, what you want to do is have your link buttons perform a window open script, instead of directly running the file transfer, like the following.
<asp:LinkButton id="link1" runat="server" onClick="window.open('TARGETURL'); return false;" Text="LinkA" />
Replace TARGETURL with an aspx page URL. Then, create a new ASPX page for the URL you specified. It will be pretty much empty, all you need are two lines.
<%# Assembly Name="YOURFOURPARTASSEMBLYSTRINGHERE" %>
<%# Page Language="C#" Inherits"YOURNAMESPACE.DOWNLOADCODE" %>
Replace YOURFOURPARTASSEMBLYSTRINGHERE with, of course, the four-part assembly string for your code. YOURNAMESPACE.DOWNLOADCODE will be replaced with the namespace and class that you will create for the page. The class will need to inherit the base page type, I personally used LayoutsPageBase since that's a perfect thing to use in a SharePoint app. All this class needs is an OnLoad method like the following.
// Don't actually name your class DOWNLOADCODE.
public class DOWNLOADCODE : LayoutsPageBase
{
protected override void OnLoad(EventArgs e)
{
byte[] byterendered = _Filename.OpenBinary(); //More on this afterwards
Response.Clear();
Response.ClearHeaders();
Response.ClearContent();
Response.ContentType = "image/jpeg";
Response.AddHeader("Content-Disposition", "attachment;filename=abc.jpg");
Response.CacheControl = "Public";
Response.BinaryWrite(byterendered);
Response.End();
}
}
You will have to retrieve _Filename in this new page, of course. The best way to do this is to take whatever parameters you use to determine _Filename in the first place, and pass it as part of the URL query string.
Using this, clicking the link button will open a new window, but since all this page does it have a file response, it will just open the file dialog and be done with it. Meanwhile, your original aspx page will not have ended its response, so it can continue whatever function you need it to.

ASP.NET which control could wrap JS block and extractable so I could render it back to header

As title, basically I have a user control placed inside a page and then the page is placed inside the master page. I want to extract a block of javascript and put it back to the page head. When I try to wrap the code inside any block control (e.g. a div runat server) and access divID.InnerText then ASP.NET bust off with
Cannot get inner content of startup_script because the contents are not literal.
I dont want to extract JS inside cs file, thats awfully ugly approach (all sort of escapes and people wont even notice you have JS written unless they drill your CS file), what can I do?
You could store the javascript in a separate file, and then add it to the page using Page.RegisterClientScriptBlock()
Add the javascript you want to a .js file and add the .js file to your project.
Alter the properties of the .js file so that it is an Embedded Resource.
Then use code like this somewhere in your UserControl (maybe the Page_Load) to pull the code from the file and drop it into the page:
string javaScript = "";
// the javascript is in a separate file which is an 'embedded resource' of the dll
using (StreamReader reader =
new StreamReader((typeof(ThisClass).Assembly.GetManifestResourceStream(typeof(ThisClass), "NameOfJavaScriptFile.js"))))
{
javaScript = String.Format("<script language='javascript' type='text/javascript' >\r\n{0}\r\n</script>", reader.ReadToEnd());
}
Page.RegisterClientScriptBlock("MyScriptBlock", javaScript);
Note that RegisterClientScriptBlock() will put the script near the top of the page, but apparently not in the page header.
(edited bit about header after comment)
<%# Page Language="C#"%>
<script runat=server>
protected override void OnLoad(EventArgs e)
{
string scriptText = someID.InnerHtml;
//if you really want it in the header...
//Page.Header.Controls.Add( new LiteralControl(String.Format( "<scr" + "ipt language=\"javascript\">{0}</scri" + "pt>\\n", scriptText )));
//doesnt add to header and requires form runat=server
Page.ClientScript.RegisterStartupScript(this.GetType(), "SomeScript", scriptText, true);
base.OnLoad(e);
}
</script>
<head runat=server></head>
<form runat=server>
<div id="someID" runat=server>alert('hi');</div>
</form>
Okay, I've probably done this in a horrible, horrible way, but I wanted to add a script to the head element in a recent project from a user control. This script didn't require any data from my server, but I only wanted it on specific pages, so I put the script in a .js-file, and added it to the head like this:
HtmlGenericControl script = new HtmlGenericControl("script"); // Creates a new script-element
script.Attributes.Add("type","text/javascript");
script.Attributes.Add("src","src/to/js-file.js");
Page.Master.FindControl("head").Controls.Add(script); // Finds the element with ID "head" on the pages master page.
Not entirely sure if the code works as I think it does as the code I wrote for the project is on another machine, but you get the idea, right?
Edit:
After googling your error message for a bit, I think this might be a solution to your problem:
using System.IO;
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
yourDivID.RenderControl(h);
String str = sw.GetStringBuilder().ToString();
If you combine the two examples, you should be able to get the result you want. I haven't tested this, but it works in my head.

How do I Validate the File Type of a File Upload?

I am using <input type="file" id="fileUpload" runat="server"> to upload a file in an ASP.NET application. I would like to limit the file type of the upload (example: limit to .xls or .xlsx file extensions).
Both JavaScript or server-side validation are OK (as long as the server side validation would take place before the files are being uploaded - there could be some very large files uploaded, so any validation needs to take place before the actual files are uploaded).
Seems like you are going to have limited options since you want the check to occur before the upload. I think the best you are going to get is to use javascript to validate the extension of the file. You could build a hash of valid extensions and then look to see if the extension of the file being uploaded existed in the hash.
HTML:
<input type="file" name="FILENAME" size="20" onchange="check_extension(this.value,"upload");"/>
<input type="submit" id="upload" name="upload" value="Attach" disabled="disabled" />
Javascript:
var hash = {
'xls' : 1,
'xlsx' : 1,
};
function check_extension(filename,submitId) {
var re = /\..+$/;
var ext = filename.match(re);
var submitEl = document.getElementById(submitId);
if (hash[ext]) {
submitEl.disabled = false;
return true;
} else {
alert("Invalid filename, please select another file");
submitEl.disabled = true;
return false;
}
}
It's pretty simple using regulare expression validator.
<asp:RegularExpressionValidator
id="RegularExpressionValidator1"
runat="server"
ErrorMessage="Only zip file is allowed!"
ValidationExpression ="^.+(.zip|.ZIP)$"
ControlToValidate="FileUpload1"
> </asp:RegularExpressionValidator>
Client-Side Validation of File Types Permissible to Upload
From javascript, you should be able to get the filename in the onsubmit handler. So in your case, you should do something like:
<form onsubmit="if (document.getElementById('fileUpload').value.match(/xls$/) || document.getElementById('fileUpload').value.match(/xlsx$/)) { alert ('Bad file type') ; return false; } else { return true; }">...</form>
I agree with Chris, checking the extension is not validation of the type of file any way you look at it. Telerik's radUpload is probably your best option, it provides a ContentType property of the file being uploaded, which you can compare to known mime types. You should check for:
application/vnd.ms-excel,
application/excel,
application/x-msexcel
and for the new 2k7 format:
application/vnd.openxmlformatsofficedocument.spreadsheetml.sheet
Telerik used to sell radUpload as an individual component, but now its wrapped into the controls suite, which makes it a little more expensive, but by far its the easiest way to check for the true type
You could use a regular expression validator on the upload control:
<asp:RegularExpressionValidator id="FileUpLoadValidator" runat="server" ErrorMessage="Upload Excel files only." ValidationExpression="^(([a-zA-Z]:)|(\\{2}\w+)\$?)(\\(\w[\w].*))(.xls|.XLS|.xlsx|.XLSX)$" ControlToValidate="fileUpload"> </asp:RegularExpressionValidator>
There is also the accept attribute of the input tag:
<input type="file" accept="application/msexcel" id="fileUpload" runat="server">
but I did not have much success when I tried this (with FF3 and IE7)
As some people have mentioned, Javascript is the way to go. Bear in mind that the "validation" here is only by file extension, it won't validate that the file is a real excel spreadsheet!
Based on kd7's reply suggesting you check for the files content type, here's a wrapper method:
private bool FileIsValid(FileUpload fileUpload)
{
if (!fileUpload.HasFile)
{
return false;
}
if (fileUpload.PostedFile.ContentType == "application/vnd.ms-excel" ||
fileUpload.PostedFile.ContentType == "application/excel" ||
fileUpload.PostedFile.ContentType == "application/x-msexcel" ||
fileUpload.PostedFile.ContentType == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" //this is xlsx format
)
return true;
return false;
}
returning true if the file to upload is .xls or .xlsx
Ensure that you always check for the file extension in server-side to ensure that no one can upload a malicious file such as .aspx, .asp etc.
Well - you won't be able to do it server-side on post-back as the file will get submitted (uploaded) during the post-back.
I think you may be able to do it on the client using JavaScript. Personally, I use a third party component called radUpload by Telerik. It has a good client-side and server-side API, and it provides a progress bar for big file uploads.
I'm sure there are open source solutions available, too.
I think there are different ways to do this. Since im not familiar with asp i can only give you some hints to check for a specific filetype:
1) the safe way: get more informations about the header of the filetype you wish to pass. parse the uploaded file and compare the headers
2) the quick way: split the name of the file into two pieces -> name of the file and the ending of the file. check out the ending of the file and compare it to the filetype you want to allow to be uploaded
hope it helps :)
Avoid the standard Asp.Net control and use the NeadUpload component from Brettle Development: http://www.brettle.com/neatupload
Faster, easier to use, no worrying about the maxRequestLength parameter in config files and very easy to integrate.
As an alternative option, could you use the "accept" attribute of HTML File Input which defines which MIME types are acceptable.
Definition here
Your only option seems to be client-side validation, because server side means the file was already uploaded. Also the MIME type is usually dictated by the file extension.
use a JavaScript Framework like jQuery to overload the onsubmit event of the form. Then check the extension. This will limit most attempts. However if a person changes an image to extension XLS then you will have a problem.
I don't know if this is an option for you, but you have more client side control when using something like Silverlight or Flash to upload. You may consider using one of these technologies for your upload process.
As another respondent notes, the file type can be spoofed (e.g., .exe renamed .pdf), which checking for the MIME type will not prevent (i.e., the .exe will show a MIME of "application/pdf" if renamed as .pdf). I believe a check of the true file type can only be done server side; an easy way to check it using System.IO.BinaryReader is described here:
http://forums.asp.net/post/2680667.aspx
and VB version here:
http://forums.asp.net/post/2681036.aspx
Note that you'll need to know the binary 'codes' for the file type(s) you're checking for, but you can get them by implementing this solution and debugging the code.
Client Side Validation Checking:-
HTML:
<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:Button ID="btnUpload" runat="server" Text="Upload" OnClientClick = "return ValidateFile()" OnClick="btnUpload_Click" />
<br />
<asp:Label ID="Label1" runat="server" Text="" />
Javascript:
<script type ="text/javascript">
var validFilesTypes=["bmp","gif","png","jpg","jpeg","doc","xls"];
function ValidateFile()
{
var file = document.getElementById("<%=FileUpload1.ClientID%>");
var label = document.getElementById("<%=Label1.ClientID%>");
var path = file.value;
var ext=path.substring(path.lastIndexOf(".")+1,path.length).toLowerCase();
var isValidFile = false;
for (var i=0; i<validFilesTypes.length; i++)
{
if (ext==validFilesTypes[i])
{
isValidFile=true;
break;
}
}
if (!isValidFile)
{
label.style.color="red";
label.innerHTML="Invalid File. Please upload a File with" +
" extension:\n\n"+validFilesTypes.join(", ");
}
return isValidFile;
}
</script>

Resources