AsyncFileUpload postback causes double upload - c#

I implemented the AsyncFileUpload control on a web page. This web page requires uploaded files to appear in a GridView.
The GridView contains the following columns: "File Name", "Confidential" Check Box, and a "Remove" button to remove the uploaded file.
Since the AsyncFileUpload postback does not do a full page postback, I need to "force" a postback on the OnClientUploadComplete event of the AsyncFileUpload control in order to render the gridview after uploading a file.
In the OnClientUploadCompleteEvent, I use javascript to call __doPostBack. In this postback, I only bind my GridView and display the file information (I don’t re-save the file).
The problem: On the AsyncFileUpload’s first “partial” postback, the file is successfully uploaded, as expected. On the second postback that I force with __doPostBack, the file is re-uploaded.
You can verify this by using Google Chrome, which displays the upload progress. The behaviour is as follows:
- After selecting the file, the progress increments from 0% to 100% and the file is uploaded.
- After this, the __doPostBack executes, and you can see the upload progress increment again from 0% to 100%.
How can I make sure the Gridview is properly populated, but that the file is not uploaded twice?
I attached a sample solution which contains the issue: https://www.yousendit.com/download/MzZFc2ZBNDRrYUN4dnc9PQ

There is a simpler solution
##t0x1n3Himself the solution u gave is very simple but does not work
surround the AsyncFileUpload with an update panel name it UpdatePanelAFU
then in the UpdatePanelAFU do as the following :
protected void AsyncFileUpload_UpdatePanelAFU(object sender,AjaxControlToolkit.AsyncFileUploadEventArgs e)
{
if (Request.Params.Get("__EVENTTARGET") != "UpdatePanelAFU")
return;
..... rest of the code
}
enjoy!

Maybe ugly, but works:
1)
Add a css-hidden asp:Button bellow the asp:AsyncFileUpload AsyncFileUpload1 control.
<asp:Button runat="server" ID="btnClick" Text="Update grid" style="display:none"/>
2)
On the Page_Load method, remove the if (Request.Params.Get("__EVENTTARGET") == "UploadPostback") and put its block in a simple else to the previous if.
3)
On the AsyncFileUpload1_UploadedComplete function, also remove the if (Request.Params.Get("__EVENTTARGET") != "UploadPostback") line, but leave intact everything that was inside it.
4)
Back to the aspx. Put a asp:UpdatePanel outside the grid GridView1.
<asp:UpdatePanel runat="server" UpdateMode="Conditional">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnClick" EventName="Click" />
</Triggers>
<ContentTemplate>
<asp:GridView ID="GridView1" ...
YOUR GRID CODE REMAINS THE SAME
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
5)
The last step is to change the AjaxUploadComplete client-side javascript function to make it trigger the postback.
Replace it with the following:
function AjaxUploadComplete() {
var btnClick = document.getElementById("btnClick");
btnClick.click();
}
Any file the user selects is uploaded only once.
All changes here are meant to be made in AjaxUpload.aspx & AjaxUpload.aspx.cs of your AjaxUpload.zip.

I believe #Veera had it right. UploadComplete was being called multiple times as the file was uploading. The following worked for me.
void AsyncFileUpload1_UploadedComplete(object sender, AsyncFileUploadEventArgs e) {
if (AsyncFileUpload1.IsUploading) return;
// rest of your upload code
}

I don't have access to your sample solution which contains the issue but i encounter a double postback too in my project with the AsyncFileUpload component.
I found a very simple workaround :
Just add:
private bool justUploaded = false;
Then:
void AsyncFileUpload1_UploadedComplete(object sender, AsyncFileUploadEventArgs e)
{
if (justUploaded) return;
justUploaded = true;
// rest of your upload code
}

I find this a more elegant solution, found here: http://forums.asp.net/t/1951566.aspx?AsyncFileUpload+uploads+twice) but below is my altered fully working code:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>AsyncFileUpload Example</title>
<script type = "text/javascript">
function uploadComplete(sender) {
$get("<%=lblMesg.ClientID%>").innerHTML = "File Uploaded Successfully";
clearContents();
}
function uploadError(sender) {
$get("<%=lblMesg.ClientID%>").innerHTML = "File upload failed.";
clearContents();
}
function clearContents() {
var span = $get("<%=AsyncFileUpload1.ClientID%>");
var txts = span.getElementsByTagName("input");
for (var i = 0; i < txts.length; i++) {
if (txts[i].type == "text") {
txts[i].value = "";
}
if (txts[i].type == "file") {
txts[i].value = "";
}
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<cc1:AsyncFileUpload OnClientUploadError="uploadError"
OnClientUploadComplete="uploadComplete" runat="server"
ID="AsyncFileUpload1" Width="400px" UploaderStyle="Modern" EnableViewState = "false"
UploadingBackColor="#CCFFFF" ThrobberID="imgLoader" OnUploadedComplete = "FileUploadComplete"
/>
<asp:Image ID="imgLoader" runat="server" ImageUrl = "~/images/loader.gif" />
<br />
<asp:Label ID="lblMesg" runat="server" Text=""></asp:Label>
</form>
</body>
</html>

AsyncFileUpload has a property that named IsUploading.
when this property is set to false, a postback will happen.
you can check this property like this:
if(AsyncFileUpload1.IsUploading)
{
..... upload codes
}

Related

Manage Edits on FileUpload Control

I have a product page. I want to add my product to my database and I want also to update my product.
I have a problem with images.
When I insert the product everithing is ok.. In my aspx page I have this code:
<span>
<asp:FileUpload ID="files" runat="server" AllowMultiple="true" />
</span>
<div runat="server" id="previewImages"></div>
and when I save my product, in code behind I have this code:
string filenm = string.Empty;
HttpFileCollection fileCollection = Request.Files;
for (int i = 0; i < fileCollection.Count; i++)
{
HttpPostedFile uploadfile = fileCollection[i];
if (uploadfile.ContentLength > 0)
{
string filename = uploadfile.FileName;
System.IO.Directory.CreateDirectory(Server.MapPath("immScarpe/" + txtStyle.Text));
file.SaveAs(Server.MapPath("immScarpe/" + txtStyle.Text + "/") + fileName);
//this is pseudo-code
INSERT INTO PRODUCT_IMM (IdProduct, Path) VALUES (Id, "immScarpe/" + txtStyle.Text + "/" + fileName)
}
}
Now, the problem is that I can EDIT the saved product. When I click the edit button for a product, I have to load all it's data and let the user modify them. Also the images.
the main question is: How can I load the saved images in asp:FileUpload control?
Another thing I would like to do is to show images previews...in insert and in edit.
An Example of what I want to do is the thing that amazon does
but, if it's possible with only one FileUpload with AllowMultiple = true
I am willing to use other technologies like javascript, jquery and Ajax if it's necessary
Show Images Preview - Insert
<script src="jquery-1.10.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
function ShowpImagePreview(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#previewImage').attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
</script>
<asp:Image ID="previewImage" runat="server" />
<asp:FileUpload ID="FileUpload1" runat="server" onchange="ShowpImagePreview(this);" />
Here is a very basic example as to how you can handle images after they have been send to the server. In this snippet the filename of the image is fixed, but it should be enough to give you push in the right direction.
protected void Page_Load(object sender, EventArgs e)
{
//check if the file exists and show
if (File.Exists(Server.MapPath("testImage.jpg")))
{
setImage("/testImage.jpg");
}
}
//upload a new image
protected void Button1_Click(object sender, EventArgs e)
{
if (FileUpload1.HasFile)
{
try
{
FileUpload1.SaveAs(Server.MapPath("testImage.jpg"));
setImage("/testImage.jpg");
}
catch
{
//error writing file
}
}
}
//delete the image
protected void LinkButton1_Click(object sender, EventArgs e)
{
try
{
File.Delete(Server.MapPath("testImage.jpg"));
LinkButton1.Visible = false;
Image1.Visible = false;
}
catch
{
//error deleteing file
}
}
//set the image and show the delete link
private void setImage(string image)
{
Image1.ImageUrl = "/testImage.jpg";
Image1.Visible = true;
LinkButton1.Visible = true;
}
ASPX
<asp:Image ID="Image1" runat="server" Visible="false" />
<br />
<asp:LinkButton ID="LinkButton1" runat="server" Visible="false" OnClick="LinkButton1_Click">Delete image</asp:LinkButton>
<br />
<br />
<asp:FileUpload ID="FileUpload1" runat="server" />
<br />
<asp:Button ID="Button1" runat="server" Text="Upload" OnClick="Button1_Click" />
For displaying images to GridView from disk
https://www.aspsnippets.com/Articles/Display-Images-in-GridView-Control-using-the-path-stored-in-SQL-Server-database.aspx
Now you have the images shown, you want to have some replace or delete functionality on the images. You need to convert your field on the GridView for image to Template Field. You can do this by clicking on the source view of your ASPX page and replacing your ImageField or BoundField (whichever field you used in displaying the image).
See the design of the GridView on the question:
How to display image inside gridview template field without using handler class?
The way to bind the image source is in the answers in that question.
To have a delete or replace functionality, you can include a LinkButton control inside your TemplateField below the tag that displays the image.
You can set the LinkButton's CommandName property to 'Delete' or 'Replace' then on your .vb or .cs file, find the 'RowCommand' event for your GridView.
It goes something like (pseudo code only)
Protected Sub GridView_RowCommand(ByVal sender As Object, ByVal e As System.GridViewCommandEventArgs) Handles GridView.RowCommand
If e.CommandName = 'Delete' Then
'Place your delete query for your image record on the database here..
'Place your delete file from disk code here..
End If
End Sub
More info on GridView RowCommand Event
https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.rowcommand(v=vs.110).aspx

asp:FileUpload losing selected file on PostBack [duplicate]

I have asp.net FileUpload control inside an update panel. When I click upload button, I am reading the file for some code, if code not found then I am showing ModalPopup for selecting a user from dropdown, otherwise uploading and emailing the file to user of that Code(this code is saved in Database).
If code not found,its displaying ModalPopup and removing the selected file, I want to persist the selected file after post back.
This is my code
<asp:UpdatePanel ID="UpdatePanel3" runat="server" >
<ContentTemplate>
<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:RequiredFieldValidator ID="rfvFileupload" ValidationGroup="validate" runat="server" ErrorMessage="* required" ControlToValidate="FileUpload1"></asp:RequiredFieldValidator>
</ContentTemplate>
</asp:UpdatePanel>
and on Button Click
protected void btnupload_Click(object sender, EventArgs e)
{
//Reading the file and Checking from Database
if(codefound)
{
//Sending email to the user of the Code
}
else
{
ModalPopupExtender1.Show();
}
}
How can I persists the value of Upload control on post back?
Background::
When a file is selected using FileUpload Control ,then on postback, PostedFile property gets initialized with HttpPostedFile object for the file. Since http request cannot maintain state, so it looses it's state.
NOTE: FileUpload control will not work with asynchronous postback.So a postback is needed to get the file. One way is to set the triggers for your Upload button, i.e. <asp:PostBackTrigger > & NOT <asp:AsyncPostBackTrigger>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:FileUpload ID="fileUploadImage" runat="server"></asp:FileUpload>
<asp:Button ID="btnUpload" runat="server" Text="Upload Image"
OnClick="btnUpload_Click" />
</ContentTemplate>
<Triggers>
<asp:PostBackTrigger ControlID="btnUpload" />
</Triggers>
</asp:UpdatePanel>
And your Upload button code:
protected void btnUpload_Click(object sender, EventArgs e)
{
if (fileUpload1.HasFile)
{
fileName = fileupload1.FileName;
fileUpload1.SaveAs("~/UploadedContent/" + fileName);
}
}
TO PERSIST THE VALUE OF FILEUPLOAD CONTROL, you can store the fileupload object altogether in session and after postback retrieve the values you require from session.
protected void Page_Load(object sender, EventArgs e)
{
// store the FileUpload object in Session.
// "FileUpload1" is the ID of your FileUpload control
// This condition occurs for first time you upload a file
if (Session["FileUpload1"] == null && FileUpload1.HasFile)
{
Session["FileUpload1"] = FileUpload1;
Label1.Text = FileUpload1.FileName; // get the name
}
// This condition will occur on next postbacks
else if (Session["FileUpload1"] != null && (! FileUpload1.HasFile))
{
FileUpload1 = (FileUpload) Session["FileUpload1"];
Label1.Text = FileUpload1.FileName;
}
// when Session will have File but user want to change the file
// i.e. wants to upload a new file using same FileUpload control
// so update the session to have the newly uploaded file
else if (FileUpload1.HasFile)
{
Session["FileUpload1"] = FileUpload1;
Label1.Text = FileUpload1.FileName;
}
}
This problem is somewhat well documented, the update panel is listed as not working with certain controls.
File upload, and tree view being 2 of the biggies.
To make it work you should use Triggers/PostbackTrigger
<asp:UpdatePanel ID="UpdatePanel3" runat="server" >
<ContentTemplate>
<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:RequiredFieldValidator ID="rfvFileupload" ValidationGroup="validate" runat="server" ErrorMessage="* required" ControlToValidate="FileUpload1" />
<asp:Buton ID="btnupload" runat="server" Text="Upload" onclick="btnupload_Click"></asp:Button>
</ContentTemplate>
<Triggers>
<asp:PostBackTrigger ControlID="btnupload"/>
</Triggers>
</asp:UpdatePanel>
try add
$('form').attr('enctype', 'multipart/form-data');

Easy wait script

I'm trying to implement in my web form an easy wait function, it works, but not as I would.
My code is this:
for(int i = 0; i<5; i++)
{
Label1.Text = "Invio: " +i;
System.Threading.Thread.Sleep(6000);
}
The problem is that Label Text doesnt' change every 6 seconds.
This script should use 30second and change the label text in this manner:
"Invio: i" every 6 seconds.
Instead it waits 6 seconds and then it change the text in "Invio 4".
Why?
The reason this happens is because of the view state . Before you render your page the back-end code is executed, after it finishes, the DOM start to render and then your page is ready. That means your page won't refresh the label value every N seconds, because it has been already set. If you want to change the value of this dynamically you should use some front-end method as JavaScript or jQuery. If you want this approach - comment so I can make a fiddle for you.
Also this would be helpful for you - ViewState
Here is a fiddle to check if you want something like this - Fiddle demo
var count = 1;
time = setInterval(function(){
document.getElementById("label1").innerHTML="Indio: " + count;
count+= 1;
if (count == 5)
{
clearInterval(time);
}
},6000);
Back end like this:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Timer1_Tick(object sender, EventArgs e)
{
Label txt = Label1;
int i = Convert.ToInt32(txt.Text);
if (i == 4)
{
Timer1.Enabled = false;
}
else
{
i++;
Label1.Text = i.ToString();
}
}
}
and front-end is like this:
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Timer ID="Timer1" runat="server" OnTick="Timer1_Tick" Enabled="true" Interval="6000">
</asp:Timer>
<asp:Label ID="Label2" runat="server" Text="Invio: "></asp:Label>
<asp:Label ID="Label1" runat="server" Text="0"></asp:Label>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Timer1" />
</Triggers>
</asp:UpdatePanel>
</asp:Content>
This will loop 5 times with a 6 second interval.
Timer on page will trigger a postback, server side will execute and will update an updatepanel.
Unfortunately there is no easy way of doing that kind of thing purely using basic Asp.Net webforms (unless you use Asp.Net Webforms AJAX - which I personally find very confusing).
Assuming you are trying to provide some feed back to your user, about a long running operation, I'd use a combination of javascript (using JQuery Ajax for example) and a simple page to poll if the task is done, then redirect to result page.

Page with Ajax refreshes window title to be RGICLLayout3

I don't know if this is typical, SharePoint related or soemthing else, but I'm finding that with some simple Ajax on a page, after the code has finished executing, the page/window title is 'RGICLLayout3'.
i.e. I have an .aspx page with title "My Site - my page", and on there I have some controls, one of which lazy loads using JavaScript/Ajax. When that control finishes loading, the window/page title changed from 'My Site - my page' to be 'RGICLLayout3'.
Anyone seen this before? Googling 'RGICLLayout3' shows zero results.
QMKevin
[update]
here some general code to explain what I'm doing:
<asp:UpdatePanel ID="up" runat="server" UpdateMode="Conditional" OnPreRender="up_PreRender">
<ContentTemplate>
...
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdateProgress ID="updProgressTab" runat="server" AssociatedUpdatePanelID="up" >
<ProgressTemplate>
...
</ProgressTemplate>
</asp:UpdateProgress>
<script language="javascript" type="text/javascript">
function pageLoad(sender, e) {
if (!e.get_isPartialLoad()) {
__doPostBack('<%= up.ClientID %>', 'aaaa');
}
}
</script>
and then in the codefile
protected void up_PreRender(object sender, EventArgs e)
{
if (Request["__EVENTTARGET"] == up.ClientID && Request.Form["__EVENTARGUMENT"] == "aaaa")
{
System.Threading.Thread.Sleep(1000);
upPanel.Visible = true;
updProgressTab.Visible = false;
}
}
This does what I need, mostly, but as I said, once the JavaScript force Postback is complete, the page title is changed. Hopefully this make my situation clearer, but ask for further clarification if needed.

Ajax and simple button Event handlers not working

I am running into a problem with Ajax and C# asp.net. I am using Microsoft Visual Studio 2010.
First let me explain my web page.
I have script manager, and directly underneath that I have a update panel.
This is the dynamic placeholder I've been fiddling with.
http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
Within my update panel, I have a dynamic control & a button.
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<asp:ScriptManager ID="ScriptManager1" runat="server" >
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<DBWC:DynamicControlsPlaceholder ID="DynamicControlsPlaceholder1"
runat="server">
</DBWC:DynamicControlsPlaceholder>
<br />
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
</asp:Content>
Now in my code behind:
I simply add 5 text boxes to a dynamic control. Page load;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
ViewState["id"] = 0;
int id = (int)ViewState["id"];
for (int i = 0; i < 5; i++)
{
id++;
TextBox txt = new TextBox();
txt.ID = id.ToString();
DynamicControlsPlaceholder1.Controls.Add(txt);
txt.Text = i.ToString();
}
ViewState["id"] = id;
}
}
Now all my button does is add another TextBox to the dynamic control pannel.
protected void Button1_Click(object sender, EventArgs e)
{
int id = (int)ViewState["id"];
TextBox txt = new TextBox();
txt.ID = id.ToString();
DynamicControlsPlaceholder1.Controls.Add(txt);
// DynamicControlsPlaceholder1.DataBind();
txt.Text = id.ToString();
id++;
ViewState["id"] = id;
}
* Note I am using a custom dynamic control panel so their ID's are saved to the next page even though we have them creeated in a !Page.IsPostBack
The problem is that my button event handler only works once. I'm pretty sure its because the Ajax is calling a partial postback and it's not recognizing it to call my button event handler.
I'm not sure, any help is appriciated.
Firebug works wonders for debugging ajax. "There were multiple controls with the same ID '5'."
What a simple fix. Moved id++; to the top of Button1_Click event handler.
If you're ever assuming ajax is breaking your event handler just because the breakpoint is not firing in the event handler, firebug may save you too!
There was absolutely nothing wrong with the event handler, but the code within it was causing an error and ajax wasn't allowing it to break.

Categories

Resources