Label text not updating during file transfer ASP.NET - c#

I am having troubles trying to update a label during a fileupload file transfer. I essentially am trying to keep a running tab on the status of the file transfer. For whatever reason however I cannot get the label to update inside the function that I am initiating the background worker to do the file transfer. I can change the Label.Text before it enters the else statement before the file transfer (this is the part that states that there is a duplicate of a file in the desired directory).
I've been looking around for an answer for approximately two days and the conventional methods of putting the Label into an UpdatePanel and setting the UpdateMode="Conditional" and then manually calling UpdatePanel1.Update() did not work.
Other questions also addressed the problem of having errant javascript in the page and that is not the case in this situation. I do not have any javascript on this web page.
I have also tried setting the Label.Text through both a ui background worker and through a loop that ran in the SaveFile() method after the background worker for the fileupload was started. Neither worked.
Also of note I have noticed that the Label.Text contents will update when I assign it through any medium, but it does not refresh the UI on the client side until the file transfer completes, which renders the progress report in the label moot.
Here is the HTML snippet
<form id="form1" runat="server">
<!-- Here's all of the contents for the asp part of the page -->
<br />
<h1>Upload File</h1>
<asp:ScriptManager ID="ScriptMgr" runat="server"></asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="true">
<ContentTemplate>
<p>
<asp:Label ID="UploadLabel" runat="server"></asp:Label>
</p>
</ContentTemplate>
</asp:UpdatePanel>
<asp:FileUpload ID="UploadFile" runat="server"/>
<br />
<!-- OnClick="BtnUpload_Click" -->
<asp:Button ID="BtnUpload" runat="server" Text="Upload File" OnClick="BtnUpload_Click" />
<br />
<br />
<asp:Label ID="RebootLabel" runat="server" Text=""></asp:Label>
<br />
<asp:Button ID="BtnReboot" runat="server" Text="Reboot" OnClick="BtnReboot_Click" />
</form>
Here is the relevant .cs methods
protected void SaveFile(HttpPostedFile file)
{
try
{
String savePath = Resources.Resource.INSTALLER_PATH + UploadFile.FileName; //save path on the server
//check to see if there are any duplicate file names in the destination
if (System.IO.File.Exists(savePath))
{
//then the file already exists and we should notify the user
//do not write anything to the directory if this occurs
UploadLabel.Text = "A file with the desired name already exists in the destination directory, please choose another file";
}
else
{
//then it is safe to upload the file to the TOD
/*UploadLabel.Text = "Uploading file...";
BtnReboot.Enabled = false;
System.Drawing.Color temp = BtnReboot.BackColor;
BtnReboot.BackColor = System.Drawing.Color.Black;
UploadFile.SaveAs(savePath); //upload the file to the TOD
BtnReboot.BackColor = temp;
BtnReboot.Enabled = true;
UploadLabel.Text = "Finished uploading file.";*/
try
{
UploadLabel.Text = "Uploading file...";
uploadingFileName = savePath; //get the path that is being uploaded to
uploadingFileSize = UploadFile.PostedFile.ContentLength; //get the size in bytes to upload
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += Bgw_DoWork;
bgw.RunWorkerAsync();
//progress report ui worker
BackgroundWorker uiWorker = new BackgroundWorker();
uiWorker.DoWork += UiWorker_DoWork;
uiWorker.RunWorkerAsync();
bgw.Dispose();
uiWorker.Dispose();
}
catch (Exception err)
{
UploadLabel.Text = err.ToString();
}
}
}
catch (System.Web.HttpException err)
{
UploadLabel.Text = "Exception: " + err.ToString();
}
catch (System.InvalidOperationException err)
{
UploadLabel.Text = "Exception: " + err.ToString();
}
catch (System.UriFormatException err)
{
UploadLabel.Text = "Exception: " + err.ToString();
}
}
private void UiWorker_DoWork(object sender, DoWorkEventArgs e)
{
while(uploadingFileSize != 0)
{
//redraw the label
if (File.Exists(uploadingFileName))
{
FileInfo fi = new FileInfo(uploadingFileName);
long currentSize = fi.Length;
UploadLabel.Text = "Progress: " + currentSize + " / " + uploadingFileSize;
UpdatePanel1.Update();
}
}
}
/// <summary>
/// Bgw_DoWork
/// Asynchronous function that gets called for the background worker to start work
/// Is used for file uploading. Combined with the timer to give feedback on current upload progress
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Bgw_DoWork(object sender, DoWorkEventArgs e)
{
UploadLabel.Text = "Hello from the bgw";
UploadFile.SaveAs(uploadingFileName);
uploadingFileSize = 0;
uploadingFileName = "";
//BackgroundWorker worker = sender as BackgroundWorker;
//worker.ReportProgress(0);
}

The main problem is that you want to do the both actions (Uploading file and updating the label) with the same request. Consider the fact that once you upload a file you're sending a stream of bytes to the server and you need to wait for the response and the response would be after file being completely uploaded. So what you need to do is triggering 2 ajax requests throw jquery( $.ajax() method) or XMLHttpRequest. Using update panels is not an option for what you're up to do.
Take a look into this to see how you can do it : http://abandon.ie/notebook/simple-file-uploads-using-jquery-ajax

Related

How to access the value attribute of a progress tag from backend code

I'm trying to make a progress bar to display during some "modifying" we are doing to 200,000+ rows from an excel document. I just wanted to try something simple, but I can't seem to get the value attribute from the progress tag.
For example if I had something simple like:
<asp:UpdatePanel ID="upnlPercent" runat="server">
<progress id="progressPercent" runat="server"></progress>
</asp:UpdatePanel>
And:
public static void CleanExcelSheet()
{
for(int i = 0; i < rows.Count; i++)
{
... // Clean whatever
progressPercent.Value = i / rows.Count;
upnlPercent.Update();
}
}
Is anyone aware of a simple way I could handle something like this? I'm open to other suggestions also if this doesn't really seem like a viable solution.
Thanks a bunch!
what you would want to do, is store the percent in a session var Session["percent"], and set a Load handler to your update panel where you would update the progress from the session var.
on client side, you would use javascript to make the update panel post back and update each certain amount of miliseconds.
an important thing to remember, is to run your cleaning function on a separate thread so it would not block your app, and allow the app to listen to post backs from the update panel.
here is an example of how to do it:
aspx:
this is our update panel with an element inside which we will update
<asp:UpdatePanel ID="UpdatePanel1" runat="server" OnLoad="UpdatePanel1_Load">
<ContentTemplate>
<label id="Label_For_Server_Time" runat="server"></label>
</ContentTemplate>
</asp:UpdatePanel>
<asp:Button ID="Button1" runat="server" Text="Click Me" OnClick="Button1_Click" />
in your aspx header, add the following code:
this code calls the built-in asp.net postback function on the update panel, it will fire the Load handler of the update panel without refreshing the whole page
<script type="text/javascript">
window.onload = function () {
setInterval("__doPostBack('<%=UpdatePanel1.ClientID%>', '');", 1000);
}
</script>
code behind:
this is the load handler for the update panel, it fires everytime the panel is posting back from the aspx page, we are checking if the session var exists, and setting the label text:
protected void UpdatePanel1_Load(object sender, EventArgs e)
{
if (Session["percent"] != null)
{
Label_For_Server_Time.InnerText = Session["percent"].ToString();
}
}
this is your function, we are running it on a separate thread to not block the app and setting the session var accordingly.
public void CleanExcelSheet()
{
new Thread(delegate()
{
for (int i = 0; i < 100000000; i++)
{
//... your cleaning here
float _f = (float)i / 100000000;
Session["percent"] = _f;
}
}).Start();
}
protected void Button1_Click(object sender, EventArgs e)
{
CleanExcelSheet();
}
On the server side, the type of progressPercent is HtmlGenericControl, which allows you to get/set properties like this:
progressPercent.Attributes["value"] = (i / rows.Count).ToString();
Or if the attribute is not already present, you may have to do the following:
progressPercent.Attributes.Add("value", (i / rows.Count).ToString());

Open Link in New Tab in ASP.NET

I'm trying to use a Button to open a link in a new tab in ASP.NET. I'm trying the following but it isn't working:
<asp:Button ID="ReportButton" runat="server" CssClass="button" Font-Size="XX-Large" ForeColor="White" Text="Report" OnClick="ReportButton_Click" OnClientClick="form1.target='_blank';" />
In the code, ReportButton_Click is defined as follows:
protected void SkidPackReportButton_Click(object sender, EventArgs e)
{
GoToPage(LocationSkidPackReportPage);
}
and GoToPage is defined as follows:
bool GoToPage(string page)
{
try
{
Response.Redirect(page);
return true;
}
catch (Exception)
{
StatusLabel.Text = "There was an error finding the page.";
return false;
}
}
Don't do server-side Response.Redirect, just do a client-side window.open. E.g.
void GoToPage(string page) {
ScriptManager.RegisterStartUpScript(this, this.GetType(), "newPage", String.Format("window.open({0});", page), True);
}
Or better yet - avoid postback altogether. You can assign clientClick to your button like:
ReportButton.OnClientClick = String.Format("window.open({0});return false;", LocationSkidPackReportPage);
This way new page will be opened on client without need to go back to the server.
Make LocationSkidPackReportPage a public property in code behind and then replace your button by:
Report
OR, if you need to fill this var in code behind:
// Response.Redirect(page); -> Replace this by:
string script = String.Format("window.open('{0}', '_blank');", LocationSkidPackReportPage);
ScriptManager.RegisterStartUpScript(this, this.GetType(), "reportResultPage", script, True);
this work for me
Page.ClientScript.RegisterStartupScript(
this.GetType(), "OpenWindow", "window.open('../_Reportes/ReporteGeneral.aspx','_newtab');", true);

Page.Unload Event inside a Update Panel

I have a Image Button declared as,
<div>
<asp:ImageButton ID="btnDoWork" runat="server" ImageUrl="/_LAYOUTS/1033/IMAGES/row.png" ValidationGroup="Page" />
</div>
<div>
<asp:RequiredFieldValidator runat="server" ID="reqName" ControlToValidate="txtEmail" ValidationGroup="Page" ErrorMessage="enter a email" />
<asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server" ValidationExpression="^([\w\.\-]+)#([\w\-]+)((\.(\w){2,3})+)$" ControlToValidate="txtEmail" ValidationGroup="Page" ErrorMessage="enter a email" />
</div>
within a update panel,
now in code behind I am doing something like this,
btnDoWork = (ImageButton)this.control.FindControl("btnDoWork"); //this code is in childcontrols method
btnDoWork.Click += new ImageClickEventHandler(btnDoWork_Click);
then
protected void btnDoWork_Click(object sender, ImageClickEventArgs e)
{
//Process a bit of code and at end,
this.Page.Unload += new EventHandler(Page_Unload_MessageBox);
and then in button click event,
public static void Page_Unload_Page_Unload_MessageBox(object sender, EventArgs e)
{
System.Globalization.CultureInfo _culture = Thread.CurrentThread.CurrentUICulture;
StringBuilder sb = new StringBuilder();
sb.Append("<script language=\"javascript\">");
sb.Append("$('body').append(\"<div id='M'><span id='text'>" +
SPUtility.GetLocalizedString("$Resources:abc", "def", (uint)_culture.LCID) +
"</span><br/><div id='BB' onclick='return BB();'><a href='' onclick='return BB();'>" +
SPUtility.GetLocalizedString("$Resources:OK", "def", (uint)_culture.LCID) +
"</a></div></div>\");");
sb.Append("function BB() { $('#M').remove(); $('#E').remove(); return false; }");
sb.Append("function dM(){ var browser = navigator.appName; if (browser == 'Netscape') { $('#M').css({ 'top': '5%' }, 500); } }");
sb.Append("</script>");
// Write the JavaScript to the end of the response stream.
HttpContext.Current.Response.Write(sb.ToString());
Now if I put email address I get error while when it tries to Response.Write I think, I wonder what alternative is there, e.g. can I use triggers in update panel or any other event or something..
here's the error I am getting now,
Note: I changed all variable names so don't get confused if something doesn't match
The message is very clear, you can not add this command HttpContext.Current.Response.Write on update panel, and that because can not know how to handle it, because the update panel is return a struct that is used by the javascript to redraw some part of the page.
The solution is to add a literal control inside the UpdatePanel, in the place you wish to add the extra html code, and write that control the render as:
txtLiteralID.Text = sb.ToString();
How ever, here you have a diferent situation than the normal, you won to render and run a script.
The main problem is how to trigger the script to run. The only way is to use the UpdatePanel handler that is this standard code:
<script type="text/javascript">
// if you use jQuery, you can load them when dom is read.
$(document).ready(function () {
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_initializeRequest(InitializeRequest);
prm.add_endRequest(EndRequest);
});
function InitializeRequest(sender, args) {
}
function EndRequest(sender, args) {
// after update occur on UpdatePanel run the code.
UnloadMsgBox();
}
</script>
Now on the EndRequest you need to call your script, where it may all read exist in your code as:
function UnloadMsgBox()
{
// render your code of the javascript.
$('body').append(\"<div id='M'><span id='text'></span><br/><div id='BB' onclick='return BB();'><a href='' onclick='return BB();'></a></div></div>\");
function BB() { $('#M').remove(); $('#E').remove(); return false; }"
function dM(){ var browser = navigator.appName; if (browser == 'Netscape') { $('#M').css({ 'top': '5%' }, 500); } }"
}
and not need to render it on UpdatePanel.
To summarize:
On the update panel you can not use the Response.Write to render something but a literal control, that renders inside him.
On the update panel you can not render javascript code and expect to run, to run a javascript code you need to use the EndRequest handler that comes with the UpdatePanel.
MS Ajax calls perform full page rendering, calculate the diff from the original, send the diff to the client, and magically merge the diff in the browser.
If you just send javascript as response, it's something the framework does not expect and it throws the message.
See a previous answer on how to invoke javascript from an UpdatePanel.

How to create custom control of existing user control

I have created one user control for multiple file upload ,
i need to create its custom control so that I can have a dll of that control.
What are the ways that I can do this?
usercontrol.ascx
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script src="Scripts/jquery.MultiFile.pack.js" type="text/javascript"></script>
<div><%-- accept attribute can be used like accept="png|jpg"--%>
Multiple File Upload<br />
<asp:FileUpload ID="FileUpload10" runat="server" class="multi" accept="" />
<asp:Button ID="Button3" runat="server" Text="Submit" OnClick="jQueryUploadFiles" />
<br />
<asp:Label ID="lblMessage" runat="server" EnableViewState="false" ForeColor="Green" />
<br />
<asp:Label ID="lblError" runat="server" EnableViewState="false" ForeColor="Red" />
</div>
usercontrol.ascx.cs
private void FileUploadUsingJQuerySelectionMethod()
{
// check if file has been selected
HttpFileCollection files = Request.Files;
for (int i = 0; i < files.Count; i++)
{
HttpPostedFile file = files[i];
if (file.ContentLength > 0)
{
string path = ConfigurationManager.AppSettings["FilePath"];
string fileName = Path.GetFileName(file.FileName);
// now save the file to the disk
file.SaveAs(path + fileName);
lblMessage.Text += "File : <b>" + fileName + "</b> uploaded successfully !<br />";
}
}
}
I tried like following:
public class MultipleFileUpload : WebControl
{
#region declare controls here
Label lblMessage;
Label lblError;
FileUpload FileUpload10;
Button btnUpload;
#endregion
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string FilePath
{// prop to get filepath
get
{
String s = (String)ViewState["FilePath"];
return ((s == null) ? "[" + this.ID + "]" : s);
}
set
{
ViewState["FilePath"] = value;
}
}
protected override void RenderContents(HtmlTextWriter output)
{
output.Write(FilePath);
}
// create the layout (html) of your control here
// all the HTML code including <div>
// Add all controls to the <div>, below code is very crude.<br/>
// Also you need to register the script tags and add the script to it<br/>
protected override void CreateChildControls()
{
base.CreateChildControls();
Table table = new Table();
this.Controls.Add(table);
lblMessage = new Label();
lblMessage.ID = "lblMessage";
lblError = new Label();
lblError.ID = "lblError";
FileUpload10 = new FileUpload();
FileUpload10.ID = "FileUpload10";
btnUpload = new Button();
btnUpload.ID = "btnUpload";
btnUpload.Text = "Submit <br/> ";
// table.Controls.Add(lblMessage);
}
// invoke this method were ever required
private void FileUploadUsingJQuerySelectionMethod()
{
// check if file has been selected
HttpFileCollection files = HttpContext.Current.Request.Files;
for (int i = 0; i < files.Count; i++)
{
HttpPostedFile file = files[i];
if (file.ContentLength > 0)
{
string path = FilePath;
string fileName = Path.GetFileName(file.FileName);
// now save the file to the disk
file.SaveAs(path + fileName);
lblMessage.Text += "File : <b>" + fileName + "</b> uploaded successfully !<br />";
}
}
}
You can put your control in a dll following the steps detailed here: Turning an .ascx User Control into a Redistributable Custom Control.
I think that it would be worth converting your user control to a proper server control, however, it's not that hard and you would end up with easier to maintain code (as you will see, the process described there is rather awkward).
You could add the js files by embedding them in the dll i.e.
Including them as normal in the custom control project
Right clicking and selecting 'embedded resources'
Accessing through the resource manager as they are now part of the default resource file i.e.
Stream ms = Assembly.GetExecutingAssembly()
.GetManifestResourceStream("resourcename including namespace");
Then read the stream to get the script as a string
Register the script string with ScriptManager in the usual way
To build a web control you need to inherit from UserControl or another control, in your case FileUpload, then override the init event to add other controls (e.g. button) to the tree. Override any other events as needed.
Old article but pretty clear e.g. of principal:
http://www.codeproject.com/KB/validation/textboxwithvalidator.aspx

Print the Report without showing the data

How can i print the Report without showing the data, that mean just paper output no screen output.
in my Master page i put a iframe:
<iframe id="reportout" width="0" height="0" />
</form>
and in my Ford.aspx:
<script type="text/javascript">
// Submit Button
function OnSumbitButtonClick(s, e) {
// e.processOnServer = false;
var Temp = <%= TempId %> //Get value from Server
//alert(Temp +'--'+ ASPxTextBox_NBR_COLIS.GetValue());
document.getElementById('reportout').contentWindow.location = '../Print/BonEticket_Web.aspx?OdreID=' + Temp + '&CountOrdre=' +ASPxTextBox_NBR_COLIS.GetValue();
}
</script>
<dx:ASPxButton ID="ASPxButton_save" runat="server" Image-Url="~/images/Icon/Good-or-Tick-icon.png" Text="Enregistrer" Width="110px" onclick="ASPxButton_save_Click">
<ClientSideEvents Click ="OnSumbitButtonClick" />
</dx:ASPxButton>
and in m Ford.aspx.cs:
protected void ASPxButton_save_Click(object sender, EventArgs e)
{
try
{
//Get new inserted ID from Database --> my SQL id is autoincrement
TempId = oOrdre_BL.SaveUpdt_Ordre_BL(oPersOrdr, OrdreID);
// Response.Redirect("../Print/BonEticket_Web.aspx?OdreID=" + TempId + "&CountOrdre=" + ASPxTextBox_NBR_COLIS.Text);
}
catch (Exception ex)
{
lbl_err.Text = ex.Message;
if (ex.InnerException != null) { lbl_err.Text += "-->" +ex.InnerException.Message; }
}
The problem here when i enable my javascript: e.processOnServer = false; it work, but i cannot do that because i need the calculated data from Server var Temp = <%= TempId %>
Thanks you in advance for helping me.
Internet Explorer has two events onbeforeprint and onafterprint, they do what they say.
Here's a small tutorial on them: http://www.javascriptkit.com/javatutors/ie5print.shtml
However, if you are outside enterprise environment where everybody are using IE, you'll have to get creative.
An idea I can think of is show the to-print text in a popup window that prints itself and closes.

Categories

Resources