AjaxFileUpload reloads page on upload ONLY for image files - asp.net

I have been working to debug an intermittent issue I've been experiencing with AJAXFileUpload. I'm moving our code away from another uploader and have worked this into several pages already. I have realized that the uploader is reloading the page after completing the UploadComplete code in the code-behind ONLY for images. I can upload .pdf, .docx with absolutely no problem but as soon as I try .png, .jpeg, .gif, etc the page reloads immediately after the upload.
I can't find anything that would suggest the behavior between these two types of files should be different and I'm assuming I'm missing something.
Here is my upload control:
<ajax:AjaxFileUpload AutoStartUpload="true" OnClientUploadCompleteAll="() => $('#btnSaveThumbnails').toggle()" ClientIDMode="Static" style="max-width:800px;display:none" runat="server" ID="thumbUploader" />
And here is the code-behind for the UploadComplete function:
If Not System.IO.Directory.Exists(tempFilePath) Then
System.IO.Directory.CreateDirectory(tempFilePath)
End If
sender.SaveAs(tempFilePath & e.FileName)
Session("docUploaderFiles") = If(Session("docUploaderFiles"), New List(Of String))
CType(Session("docUploaderFiles"), List(Of String)).Add(e.FileName)
Like I mentioned, these work exactly as expected for non-image file types in my experience.
UPDATE: I have narrowed it down to being caused by the .SaveAs call in the code-behind. Removing just that line causes no page reload.
UPDATE: I have found this issue is specific to my machine. The uploader works on other local environments as well as on our production application. Possibly something to do with my IIS.

I can't see why this would not work.
However, I have OFTEN found that if you don't specify and wire up the CLIENT side events, then the up-loader can barf on you.
So, try this for your test:
<ajaxToolkit:AjaxFileUpload ID="AjaxFileUpload1" runat="server"
OnClientUploadComplete="MyComplete"
OnClientUploadCompleteAll="MyCompleteAll"
OnClientUploadStart="MyStart" AllowedFileTypes="txt,zip,png,jpeg"
OnClientUploadError="MyError" ChunkSize="16384" />
</div>
<br />
<br />
</div>
<script>
function MyStart() {
}
function MyComplete() {
}
function MyCompleteAll() {
}
function MyError(e) {
}
</script>
Note how I added the client side events. I have found in some cases that without the client side events, then problems arise, so I drop in the 4 blank client side events.
EVEN if you not using the client side events, try putting them in as per above. So, I dropped in 4 client side events - without any code in those stubs.
My server side code for this test is this:
Protected Sub AjaxFileUpload1_UploadCompleteAll(sender As Object, e As AjaxControlToolkit.AjaxFileUploadCompleteAllEventArgs) Handles AjaxFileUpload1.UploadCompleteAll
Debug.Print("all done")
End Sub
Protected Sub AjaxFileUpload1_UploadStart(sender As Object, e As AjaxControlToolkit.AjaxFileUploadStartEventArgs) Handles AjaxFileUpload1.UploadStart
Debug.Print("start upload")
End Sub
Protected Sub AjaxFileUpload1_UploadComplete(sender As Object, e As AjaxControlToolkit.AjaxFileUploadEventArgs) Handles AjaxFileUpload1.UploadComplete
Debug.Print("file done")
Debug.Print(e.FileName)
End Sub
Protected Sub AsyncFileUpload1_UploadedFileError(sender As Object, e As AjaxControlToolkit.AsyncFileUploadEventArgs)
Debug.Print(e.StatusMessage)
End Sub
I would also check + clear out non ASCII chars in the file name. I seen funny files - and they blow out a error.
So, I do this:
Dim strCleanFile As String = TrimNonAscii(e.FileName)
and
Public Function TrimNonAscii(ByVal value As String) As String
Dim pattern As String = "[^ -~]+"
Dim reg_exp As Regex = New Regex(pattern)
Return reg_exp.Replace(value, "")
End Function
So I trim out spaces, and also rip out other funny values. (from a Mac or other devices, they actually allow non legal windows chars in the file name, but windows does not.

Related

Access winform variable from browsercontrol

I have an application in ASP.Net Ajax. I want to open it via a browsercontrol from a winform, and I wish to access a variable (username) that the user used to log in to the webform with. On load I would like to read that username and perform the rest of my webpage code on that browsercontrol using that username.
My ASP.Net Ajax has been published to a internal web server and the browsercontrol loads that IP address.
Is there any way to achieve this at all?
EDIT:
I have discovered the javascript extension: window.external
And I can call a C# procedure from the webpage using javascript with it, which is a start, but I need to retrieve a varaible from c# - this is where the problem comes in. I have tried the
var name = function window.external.GetGlobalVariable(MyGlobalProcedure, "Cannot Get Value");
But javascript error says the method cannot be applied to the object.
Your answer should be as follows:
Public Class Form1
Dim GlobalVar As String = "Your Name"
Dim YourBrowser As New WebBrowser
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
YourBrowser.Url = New Uri("Your URL address")
AddHandler YourBrowser.DocumentCompleted, AddressOf PageLoadComplete
End Sub
'The invokescript will only work once the HTML has finished loading itself into your WebBrowser
Sub PageLoadComplete()
'Must declare the string inside an array as the invokescript only allows an object to be sent
Dim VarToSend As String() = {GlobalVar}
YourBrowser.Document.InvokeScript("yourJavascriptfunction", VarToSend)
End Sub
The javascript section should look as follows:
<script type="text/javascript" language="javascript">
function userNameSet(name) {
$(document).ready(function() {
//variable now exists inside your WebBrowser client and can be used accordingly now
alert(name);
});
}
</script>
References for answer: http://www.dotnetcurry.com/showarticle.aspx?ID=194
"Store that name in a session variable and access the session in your ajax call"
In your ASP.Net application create a hidden field (or if it's somewhere on the UI in some control that works also). Put the username or whatever information you want to share into that field.
From your WinForms program you can request that field through the WebBrowser control like this:
MessageBox.Show(WebBrowser1.Document.GetElementById("txtUsername").GetAttribute("value"))
The above assumes you have some HTML element called txtUsername with the value attribute set.

Display query string in asp.net controls

I'm writing an ASP web application with VB back-end. What I'd like to do is generate a url and display this in control on the page. For example if I have a label and a button on the form. The label is blank. When the button is clicked the following code fires:
Protected Sub btnGenerate_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnGenerate.Click
label1.Text = "Hello"
End Sub
What I'd like to have is a url that would point to my ASP Page with the words "Hello" in the label. Is this possible?
You could do the following:
{siteaddress}/aspxpage.aspx?label=hello
then in you aspx page do something like:
<asp:label runat="server" id="yourLabelId" text='<%=Request.QueryString("label")%>' />
Or in the Page_Load:
yourLabelId.Text = Request.QueryString("label")
I would recommend validating the data before just writing it into the page.
Pass the text in query string e.g. suppose relative path of the page is /pagename.aspx , you can pass the query string as per given example below:
/pagename.aspx?text=hello
in c# write following code in Page_Load event
//You don't have to check the url all the time , so just check it if page is not posting back (first time after user visits the page and ignore all other same page post backs. Label can maintain its control state (text value) after every postback, so assign it only once to increase performance
if (!IsPostBack)
{
//Check if query string is provided or not , if it is not provided take some default text, I am taking empty string as default text.
string givenText = (Request.QueryString["text"] == null)?"":Request.QueryString["text"];
label1.Text = givenText;
}
You can also create a property for text given through query string and default text.

Deleting a folder on another thread causes webpage to not update?

I have a web app which displays a list of emails that need to be sent for the day. The user can select what emails to send, then click a button to generate them. When they click the Send button, a process gets started on another thread which generates the emails, then cleans up after itself by deleting a temp folder. Once the process is finished, the Repeater is rebound to update the User's view and remove the emails that have just been sent so they don't get sent again.
My problem is that when I delete the temp folder from my 2nd thread, the UI doesn't update with the new Repeater data. It updates correctly if I just delete the files in the folder instead of the folder itself, and it also updates correctly if I run the delete the folder on the original thread instead of the 2nd one.
New Thread code
Dim t as Thread = New Thread(New ThreadStart(AddressOf EmailLetters))
t.Start()
Delete folder code
Dim fs = Server.CreateObject("Scripting.FileSystemObject")
fs.DeleteFolder(Server.MapPath(".") + "\tmpEmailFiles")
Why won't the UI update to show the new repeater values when I delete a folder on another thread?
EDIT
Here is some sample code that shows the problem. Sorry if its a bit messy, but I just needed something simple to help me identify the problem.
When you click the button, a thread gets started and a javascript load script starts executing which does a PostBack every 10 seconds. Each postback checks if the thread is complete and updates the Status label showing the result. If I delete a folder from within the background thread, the final update to the status label never occurs. If I remove the DeleteFolder call, it does.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%# Import Namespace="System.Threading" %>
<%# Page Language="VB" Debug="true" %>
<%# Implements Interface="System.Web.UI.IPostBackEventHandler" %>
<SCRIPT language="vb" runat="server">
Sub Page_Load(Src As Object, e As EventArgs)
End Sub
Public Sub Test(src as Object, e as EventArgs)
Dim t as Thread = New Thread(New ThreadStart(AddressOf TestWorker))
t.Start()
Session("BackgroundThread") = t
End Sub
Public Sub TestWorker()
' 30 Second Delay
System.Threading.Thread.Sleep(30000)
Dim root as String = Server.MapPath(".")
Dim fs = Server.CreateObject("Scripting.FileSystemObject")
If Not fs.FolderExists(root + "\Test") Then fs.CreateFolder(root + "\Test")
fs.DeleteFolder(root + "\Test")
ErrMsg.Text = "Start: " + DateTime.Now.ToString()
End Sub
Public Sub RaisePostBackEvent(ByVal eventArgument As String) _
Implements IPostBackEventHandler.RaisePostBackEvent
If Session("BackgroundThread") is Nothing Then
Exit Sub
End If
Dim t as Thread = CType(Session("BackgroundThread"), Thread)
If t.ThreadState = ThreadState.Stopped Then
ErrMsg.Text = "Done: " + DateTime.Now.ToString()
Session("BackgroundThread") = Nothing
Else
ErrMsg.Text = "Processing: " + DateTime.Now.ToString() + " - " + t.ThreadState.ToString()
End If
End Sub
</SCRIPT>
<HTML>
<HEAD>
<SCRIPT language="javascript">
//<!--
function onLoad()
{
if(<%= IIF(Session("BackgroundThread") is Nothing, "false", "true") %>)
{
toggleLoading();
setTimeout("<%= Page.ClientScript.GetPostBackEventReference(Me, "") %>", 10000);
}
}
function toggleLoading(){
document.getElementById('imgLoading').style.display = 'block';
setTimeout("document.images['imgLoading'].src='images/loading.gif'", 100);
}
// -->
</SCRIPT>
</HEAD>
<BODY OnLoad="onLoad();">
<FORM runat="server">
<ASP:Button runat="server" Text="Test" OnClick="Test" onClientClick="javascript: toggleLoading();" />
<ASP:Label runat="server" Id="ErrMsg" />
<IMG id="imgLoading" src="images/loading.gif" style="display: none;" />
</FORM>
</BODY>
</HTML>
Figured out my problem. Turns out deleting any folder in the ASP root folder will restart the application and reset all Session variables.
To get around that I added the following to my Application_OnStart method in Global.asax
Dim p As System.Reflection.PropertyInfo = GetType(HttpRuntime).GetProperty("FileChangesMonitor", Reflection.BindingFlags.Public Or Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Static)
Dim o As Object = p.GetValue(Nothing, Nothing)
Dim f As System.Reflection.FieldInfo = o.GetType.GetField("_dirMonSubdirs", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.IgnoreCase)
Dim monitor As Object = f.GetValue(o)
Dim m As System.Reflection.MethodInfo = monitor.GetType.GetMethod("StopMonitoring", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
m.Invoke(monitor, New Object() {})
The problems is that this is a background thread on the server that is sending the emails finishes but the response has already been sent to the user. When The user opens the page the background thread is started off, and the server returns with the response on the parent thread, the background thread is still running away on the server for sometime AFTER the response has already been sent
To achieve what you want you would need to have the page refreshing on a Javascript or some ajax to poll the server and keep check if this background thread has completed. ie the background thread is started, and the user is told that emails are being proccessed, 2 seconds later the page is automatically refreshed and the user is still told emails are being processed. Finally When all emails are sent the repeater is updated and automatic refresh is disabled

CompareValidator currency check does not work with French formatted numbers

I have a salary TextBox and an associated CompareValidator, which is setup as follows:
<asp:CompareValidator ... Operator="DataTypeCheck" Type="Currency" />
I fill the TextBox with a formatted string out of the database:
txtSalary.Text = myObject.Salary.ToString("N2")
When a user accesses the page using a French culture (such as fr-ca), the ToString method will put 80 000,00 in the textbox, which is fine.
However, any number with a space in it causes the validator to fail, which is not fine. Is there any way to make the CompareValidator work properly with non-US formatted numbers?
I had a problem like you, but not quite the same, I had something like this:
<asp:RangeValidator ID="rw" ErrorMessage="error"
Text="!" ControlToValidate="r" MinimumValue="1 000,00" MaximumValue="1 000 000,00" Type="Currency" CultureInvariantValues="false" runat="server" EnableClientScript="true" />;
I databound my controls with data for example 2 000,00 and I had validation error
but when I entered a value od 2 000,00 everything was OK.
the answer was space in CurrencyGroupSeparator, my culture pl-pl has space in it, but it is not space "\x0020" but it is non breaking space "\00A0"
I've used reflector to do some digging and what I found is puzzling
currency format check is in BaseCompareValidator class in method
private static string ConvertCurrency(string text, NumberFormatInfo info)
and in code there is a line like this:
if (currencyGroupSeparator[0] == '\x00a0')
{
currencyGroupSeparator = " ";
}
I putted decompiled code in test project and tried to run it, and indeed code was not working properly.
ConvertCurrency(10000000.00m.ToString("n"), NumberFormatInfo.CurrentInfo)
returned null;
why someone put it there I don't know, but then I commented it, method have started work properly.
we cant compile .net framework from source yet, so what we can do, is to change separator from non breaking space to space
so the solution to our problem is:
Thread.CurrentThread.CurrentCulture = new CultureInfo("some culture
name");
Thread.CurrentThread.CurrentCulture.NumberFormat.CurrencyGroupSeparator
= "\x0020"; Thread.CurrentThread.CurrentCulture.NumberFormat.NumberGroupSeparator
= "\x0020";
I guess it is just a bug with the CompareValidator and RangeValidator - likely on the client side JavaScript.
I fixed the problem by changing to a CustomValidator, with the following code on the server side (and no code on the client side):
Protected Sub ValidateSalary(ByVal sender As Object, _
ByVal e As ServerValidateEventArgs)
Try
If txtSalary.Text <> String.Empty Then
Dim salary As Decimal = Convert.ToDecimal(txtSalary.Text, _
Thread.CurrentThread.CurrentUICulture)
End If
e.IsValid = True
Catch ex As Exception
e.IsValid = False
End Try
End Sub

Simulate Windows Service with ASP.NET

I have small web app that generate PDF files as a report. I'm trying to delete those generated PDF files after 10 sec that they are generated. What I want to do is to read a folder with PDF files every 10 sec, and delete all the PDF files inside that folder.
I read this post of Easy Background Tasks in ASP.NET. The following code is the VB version.
Protected Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
AddTask("DoStuff", 10)
End Sub
Private Sub AddTask(ByVal name As String, ByVal seconds As Integer)
OnCacheRemove = New CacheItemRemovedCallback(CacheItemRemoved)
HttpRuntime.Cache.Insert(name, seconds, Nothing, DateTime.Now.AddSeconds(seconds), Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, _
OnCacheRemove)
End Sub
Public Sub CacheItemRemoved(ByVal k As String, ByVal v As Object, ByVal r As CacheItemRemovedReason)
' do stuff here if it matches our taskname, like WebRequest
DeletePDFilesInFoler()
' re-add our task so it recurs
AddTask(k, Convert.ToInt32(v))
End Sub
But I got this error
Delegate
'System.Web.Caching.CacheItemRemovedCallback'
requires an 'AddressOf' expression or
lambda expression as the only argument
to its constructor.
If this code works, where I should put it. Right, now I'm putting it in the master page. How to get this error out?
Thank you
Rather than deleting them on a schedule, why not look for old PDFs and delete them each time a PDF is generated?
Pseudo-code:
/* Clean up old PDFs */
If Not StaticCleaningUpPDFsNow Then
// No other reports generating simultaneously and trying to delete old PDFs
StaticCleaningUpPDFsNow = True
For each f in (reportfolder\*.pdf)
If f.DateCreated.AddSeconds(10) < Now Then f.Delete
Next
StaticCleaningUpPDFsNow = False
End If
/* Create PDF for the current report */
...
The overhead to look for files in a folder and delete a few is incredibly small, and doing this on demand is a much better use of resources, without the hacks around cache expirations (and the edge cases that can result).
The error is in the error message, you're missing AddressOf. Try this:
OnCacheRemove = New CacheItemRemovedCallback(AddressOf CacheItemRemoved)

Resources