How to open new window with streamed document in ASP.NET Web Forms - asp.net

I have an ASP.NET Web Forms application. I want to have a button to post back to the server that will use my fields on my form (after validation) as parameters to a server process that will generate a document and stream it back to the browser. I want the form to be updated with some status results.
What is the best way to achieve this? Right now, I've got the button click generating the document and streaming it back to the browser (it's a Word document and the dialog pops up, and the Word document can be opened successfully) but the page doesn't get updated.
I have jQuery in my solution, so using js isn't an issue if that is required.

I have a very similar process on one of my servers, and the way I've handled it is to create a temporary document on the server rather than doing a live stream. It requires a bit of housekeeping code to tidy it up, but it does mean that you can return the results of the generation and then do a client-side redirect to the generated document if successful. In my case, I'm using jQuery and AJAX to do the document generation and page update, but the same principle should also apply to a pure WebForms approach.

This was way more difficult to do than I thought. The main issue is with opening a new browser window for a Word document. The window briefly flashes up, then closes - no Word document appears. It seems to be a security issue.
If i click a button on my page, I can stream the Word doc back as the response, and the browser dialog pops up allowing me to Open/Save/Cancel, but of course, my page doesn't refresh.
My final solution to this was to use a client script on the button click to temporarily set the form's target to _blank. This forces the response to the click on the postback to go to a new browser window (which automatically closes after the download dialog is dismissed):
<asp:Button Text="Generate Doc" runat="server" ID="btnGenerateDoc"
onclick="btnGenerateDoc_Click" OnClientClick="SetupPageRefresh()" />
My SetupPageRefresh function is as follows:
function SetupPageRefresh() {
// Force the button to open a new browser window.
form1.target = '_blank';
// Immediately reset the form's target back to this page, and setup a poll
// to the server to wait until the document has been generated.
setTimeout("OnTimeout();", 1);
}
Then my OnTimeout function resets the target for the form, then starts polling a web service to wait until the server process is complete. (I have a counter in my Session that I update once the process has completed.)
function OnTimeout() {
// Reset the form's target back to this page (from _blank).
form1.target = '_self';
// Poll for a change.
Poll();
}
And the Poll function simply uses jQuery's ajax function to poll my web service:
function Poll() {
var currentCount = $("#hidCount").val();
$.ajax({
url: "/WebService1.asmx/CheckCount",
data: JSON.stringify({ currentCount: currentCount }),
success: function (data) {
var changed = data.d;
if (changed) {
// Change recorded, so refresh the page.
window.location = window.location;
}
else {
// No change - check again in 1 second.
setTimeout("Poll();", 1000);
}
}
});
}
So this does a 1 second poll to my web service waiting for the Session's counter to change from the value in the hidden field on the page. This means it doesn't matter how long the server process takes to generate the Word document (and update the database, etc.) the page won't refresh until it's done.
When the web service call comes back with true, the page is refreshed with the window.location = window.location statement.
For completeness, my Web Service looks like this:
/// <summary>
/// Summary description for WebService1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class WebService1 : WebService
{
[WebMethod(EnableSession=true)]
public bool CheckCount(int currentCount)
{
if (Session["Count"] == null)
Session["Count"] = 0;
var count = (int)Session["Count"];
var changed = count != currentCount;
return changed;
}
}
Hopefully that helps somebody else!

Related

Activity Indicator is not visible on xaml page in xamarin.forms?

I have an activity indicator on xaml page. Initially its IsVisible property is false. I have a button on page. When user click on button it calls a web service to get data. I change the value of IsVisible property to true before calling the service so that activity indicator starts to display on page and after successful calling of service I change its value to again false so that it doesn't show any more on page.
But it is not working. I know the actual problem. When we call the web service the UI thread gets block and it doesn't show the activity indicator.
How I can enable the UI thread when web service gets called so that activity indicator can show on page until we get the data?
Try making your webservice call into an async and await it.
Depending on how you've structured things you may have to use a TaskCompletionSource as the following example demonstrates.
In this example when the button is clicked, the button is made invisible, and the ActivityIndicator is set to IsRunning=True to show it.
It then executes your long running task / webservice in the function ExecuteSomeLongTask using a TaskCompletionSource.
The reason for this is that in our button click code, we have the final lines:-
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
That stop the ActivityIndicator from running and showing, and also set the button back to a visible state.
If we did not use a TaskCompletionSource these lines would execute immediately after calling the ExecuteSomeLongTask if it was a normal async method / function, and would result in the ActivityIndicator not running and the button still being visible.
Example:-
Grid objGrid = new Grid()
{
};
ActivityIndicator objActivityIndicator1 = new ActivityIndicator();
objGrid.Children.Add(objActivityIndicator1);
Button objButton1 = new Button();
objButton1.Text = "Execute webservice call.";
objButton1.Clicked += (async (o2, e2) =>
{
objButton1.IsVisible = false;
objActivityIndicator1.IsRunning = true;
//
bool blnResult = await ExecuteSomeLongTask();
//
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
});
objGrid.Children.Add(objButton1);
return objGrid;
Supporting function:-
private Task<bool> ExecuteSomeLongTask()
{
TaskCompletionSource<bool> objTaskCompletionSource1 = new TaskCompletionSource<bool>();
//
Xamarin.Forms.Device.StartTimer(new TimeSpan(0, 0, 5), new Func<bool>(() =>
{
objTaskCompletionSource1.SetResult(true);
//
return false;
}));
//
return objTaskCompletionSource1.Task;
}
You need to do your work in an asynchronous way. Or in other words: Use Asnyc & Await to ensure, that you UI works well during the call.
You can find more informations in the Xamarin Docs.
async and await are new C# language features that work in conjunction
with the Task Parallel Library to make it easy to write threaded code
to perform long-running tasks without blocking the main thread of your
application.
If you need further asistance, please update your question and post your code or what you have tried so far.

Unable to get property 'value' of undefined or null reference

I have registration form and button. OnClick - I call function on server side which make a validation of user's zip code at Database with Zipcodes. If validation passed successfully - user's data stored in Database (here I continue use server function). But if ZipCode does not match - I call Javascript function where I ask if user still wants to save his data to DB. and If yes - I save it using Ajax request. Problem is when I call Javascript function - firstly it should receive user's data on client side. But when reading data happens - I receive an error "Unable to get property 'value' of undefined or null reference". But user's data still exist at the form's fields. It seems that the data that read by the server from the form once - reset somewhere - and can not be read a second time on the client.
Here is my ASP Form
<body>
<form id="frmZipValidation" runat="server">
<div>
<asp:Label runat="server">Registration Form</asp:Label>
<asp:TextBox runat="server" ID="txtbxName"></asp:TextBox>
<asp:TextBox runat="server" ID="txtbxZipCode"></asp:TextBox>
<asp:DropDownList runat="server" ID="DDLCountry">
<asp:ListItem Text="Select country" Value="Select" Selected="True"></asp:ListItem>
<asp:ListItem Text="USA" Value="USA"></asp:ListItem>
<asp:ListItem Text="Canada" Value="Canada"></asp:ListItem>
</asp:DropDownList>
<asp:TextBox runat="server" ID="txtbxState"></asp:TextBox>
<asp:TextBox runat="server" ID="txtbxCity"></asp:TextBox>
<asp:Button runat="server" ID="btnSubmit" Text="Submit" OnClick="btnSubmit_Click"/>
</div>
</form>
</body>
Here is my Server Side
public partial class Default : System.Web.UI.Page
{
string Name;
string ZipCode;
string Country;
string State;
string City;
bool IsMatch;
Addresses dbAddresses = new Addresses();
User newUser;
protected void Page_Load(object sender, EventArgs e)
{
if (Request["Action"] != null && Request["Action"].Trim() != "")
{
if (Request["Action"] == "AddUser")
{
AddUser(Request["Name"], Request["ZipCode"], Request["Country"], Request["State"], Request["City"]);
}
}
}
private void AddUser(string UserName, string UserZip, string UserCountry, string UserState, string UserCity)
{
newUser = new User(UserName, UserZip, UserCountry, UserState, UserCity);
dbAddresses.Users.Add(newUser);
dbAddresses.SaveChanges();
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
if (IsValid)
{
ZipCode = txtbxZipCode.Text;
Country = DDLCountry.Text;
State = txtbxState.Text;
City = txtbxCity.Text;
Name = txtbxName.Text;
IsMatch = false;
List<ZipCode> ZipC = (from z in dbAddresses.Zips
where z.Zip == ZipCode
select z).ToList();
//If ZipCode entered by client do not exists at Database return false
if (!ZipC.Any())
{
IsMatch = false;
}
else
{
for (int i = 0; i < ZipC.Count; i++)
{
if (ZipC[i].Country.ToString() == Country)
{
if (ZipC[i].State.ToString() == State)
{
if (ZipC[i].City.ToString() == City)
{
AddUser(Name, ZipCode, Country, State, City);
//Message to the user that all saved successfully
Page.ClientScript.RegisterClientScriptBlock(typeof(Page), "1", "<script>alert('Your data was saved successfully!');</script>");
IsMatch = true;
break;
}
else
{
IsMatch = false;
break;
}
}
else
{
IsMatch = false;
break;
}
}
else
{
IsMatch = false;
break;
}
}
}
//If user's data are not match, then go to JS client code where - If user wants in any case to save data - make it using AJAX request
if (!IsMatch)
{
string clientScript = "AjaxRequestSaveToDB();";
this.Page.ClientScript.RegisterStartupScript(this.GetType(), "MyClientScript", clientScript);
}
}
}
}
And here is Javascript:
function AjaxRequestSaveToDB()
{
var SaveData = confirm('Zip/Postal code doesn’t match region. Are you sure you want to save this data?');
if (SaveData)
{
var UserName = document.getElementById('txtbxName').value;
var UserZipCode = document.getElementById('txtbxZipCode').value;
var UserCountry = document.getElementById('DDLCountry').value;
var USerState = document.getElementById('txtbxState').value;
var UserCity = document.getElementById('txtbxCity').value;
SendDataToServer('AddUser', UserName, UserZipCode, UserCountry, USerState, UserCity);
alert("You data was saved successfully!");
}
else { alert('Not saved');
}
}
}
function SendDataToServer(RequestType, Name, ZipCode, Country, State, City)
{
var xmlHttp = getXmlHttp();
var Url = "Default.aspx?Action=" + escape(RequestType)
+ "&Name=" + escape(Name)
+ "&ZipCode=" + escape(ZipCode)
+ "&Country=" + escape(Country)
+ "&State=" + escape(State)
+ "&City=" + escape(City);
xmlHttp.open("GET", Url, true);
xmlHttp.send();
}
A short book about Client-Server Communications using "Custom" AJAX requests.
In ASP.net programming (almost) every time the client interacts with the server, the client sends all of its information to the server and then throws out its old content and replaces it with the response the client received from the server. So the problem you were running into is that your asp:button on the client machine was sending information to your .aspx page on the server and the server was interpreting the information, realizing something was wrong and telling the client it should ask the user for more information but throw out all the information that had been previously entered.
The best way that I have found to get around this problem is to use what I call "custom AJAX requests." Basically this means that we write a string of XML and send it to an ASP handler page which is set up to accept the XML string and do something with it. In my travels I have slimmed this down to basically 3 parts. The first is the user interface which contains all of the markup and CSS(and validation), the second is the JavaScript file that contains all of the data gathering and the actual AJAX request and lastly there is the ashx file that handles the request from the client.
So to start you will need to set up your user interface. Something along the lines of:
<body>
<form id="frmZipValidation" runat="server">
<div>
<div class="label">Registration Form<div>
<asp:TextBox ID="txtbxName" class="txtbxName" ClientIDMode="Static" runat="server"></asp:TextBox>
<asp:TextBox ID="txtbxZipCode" class="txtbxZipCode" ClientIDMode="Static" runat="server" ></asp:TextBox>
<asp:DropDownList ID="DDLCountry" class="DDLCountry" ClientIDMode="Static" runat="server" >
<asp:ListItem Text="Select country" Value="Select" Selected="True"></asp:ListItem>
<asp:ListItem Text="USA" Value="USA"></asp:ListItem>
<asp:ListItem Text="Canada" Value="Canada"></asp:ListItem>
</asp:DropDownList>
<asp:TextBox ID="txtbxState" class="txtbxState" ClientIDMode="Static" runat="server" ></asp:TextBox>
<asp:TextBox ID="txtbxCity" class="txtbxCity" ClientIDMode="Static" runat="server" ></asp:TextBox>
<input id="btnSubmit" class="btnSubmit" type="button" value="Save" onclick="SubmitForm()" />
</div>
</form>
</body>
Couple things to note with this:
The button to submit the form is NOT an ASP button but a HTML button.
All of the input controls are ASP controls but they have the ClientIDMode set to Static, this will only work in .NET 4.0 or higher.
We set the class to the same thing as the ID in case we aren't using .NET 4.0 or higher. Any CSS classes that you want to also add to the control can be added after the dummy ID class.(for my examples I'm assuming you are in .NET 4.0 but I can easily switch them to work without the ClientIDMode attribute if you need)
The second piece to the puzzle is the JavaScript. There are a couple ways that we can accomplish what we need. The first is by using vanilla JS without the help of any plugins or external libraries. This saves a very small amount of processing time, a marginal amount of loading time and can accomplish everything we ask of it. But, if we include an external library, JQuery, and plugin, JQuery Validation, then we can make our lives a whole heck of a lot easier during the programming phase by reducing the amount of code we have to write by a factor of about 10. And if we are really concerned about the load times then we can use the client cache to store the external libraries so that they only have to download them once. So whether or not you decide to use any external JavaScript libraries is up to what your project needs but since you are only concerned with validating that the zip code is not empty I will not use any JQuery but I just thought it would be worth mentioning because of how streamlined it makes the process.
Once you are ready to submit your form your first step will be to validate that the zipcode is valid. You can do this a couple ways depending on how in depth you want to get. The quickest check would just be to verify that the zip code text box is not empty when the button is clicked. So to do that we would just need to do:
function SubmitForm() { //This will be assigned as the click handler on your button in your HTML
if (document.getElementById('txtbxZipCode').value != null && document.getElementById('txtbxZipCode').value != '') {
Save('YourHandler', GetQueryString, GetXmlString, SuccessHandler, FailureHandler);
} else {
//Your user needs to know what went wrong...
}
}
So, down to the meat and potatoes of this whole situation. The AJAX request. I've come up with a reusable function that handles the entire AJAX request that looks like:
function Save(handlerName, GetQueryString, GetXmlString, SuccessHandler, FailureHandler) {
// Date.GetTime gets the number of milliseconds since 1 January 1970, so we divide by 1000 to get the seconds.
end = (new Date().getTime() / 1000) + 30;
//This variable is the actual AJAX request. This object works for IE8+ but if you want backwards compatability for earlier versions you will need a different object which I can dig up for you if you need.
var xmlhttp = new XMLHttpRequest();
//This is the function that fires everytime the status of the request changes.
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
//Get all the headers to determine whether or not the request was successful. This is a header you will need to add to the response manually.
var xx = xmlhttp.getResponseHeader("Success");
//the object xx will be a string that you designate. I chose to use True as the indicator that it was successful because it was intuitive.
var x1 = xx.trim();
if (x1 != undefined && x1 == 'True' && (new Date().getTime() / 1000) < end) {
//If the response was successful and the timeout hasn't elapsed then we get the XML from the response and call the success handler
var xmlResponse = xmlhttp.responseXML;
SuccessHandler(sender, xmlResponse);
} else if ((new Date().getTime() / 1000) < end) {
//If the response was not successful and the timeout hasn't elapsed then we get the XML from the response and call the failure handler
var xmlResponse = xmlhttp.responseXML;
FailureHandler(sender, xmlResponse);
} //If the request was successful
} //If the readystate is 4 and the status is 200
} //OnReadyStateChanged function
//This gets the query string to be added to the url
var varString = GetQueryString();
//Build XML string to send to the server
var xmlString = GetXmlString();
//Open the request using the handler name passed in and the querystring we got from the function passed in
xmlhttp.open("POST", "../RequestHandlers/" + handlerName + ".ashx" + varString, true);
//This tells the handler that the content of the request is XML
xmlhttp.setRequestHeader("Content-Type", "text/xml");
//Send the request using the XML we got from the other function passed in.
xmlhttp.send(xmlString);
}
This function has a built in timeout which makes it so that if the server takes more than 30 seconds to respond to a request then any response that the client receives is ignored. For my implementations this is combined with another function that displays something to the user to tell them that the website is working on their request and if the time out elapses it tells them that a time out occurred.
The second thing this function does is it assumes that all handlers will be in a folder next to the root of your website named RequestHandlers. I use this set up just to consolidate all of my handler files but you can really change where it is looking to wherever you want.
The function itself takes in a string and four function pointers. The string represents the name of the handler that will be waiting to interpret the request, the four function pointers all have very specific jobs.
The first function pointer is GetQueryString this represents a function you will have to write that will append any variables that you deem necessary to the end of the URL being posted back to. This site gives a pretty accurate explanation of what the query string should be used for. For me a common GetQueryString function looks something like:
function GetPaymentQueryString() {
var varString = '';
varString = "?CCPayment=True";
return varString;
}
The second function pointer, GetXMLString, is used to create the XML string(go figure...) that will be sent to the handler page that we are posting back to. This string will represent the bulk of the request. Everything that should not be shown to anyone snooping your requests should be sent as an XML string, if you are really paranoid you can send it as an encrypted XML string but that's not, strictly speaking, necessary. It all depends on what you are sending, if its complete credit card information then, yeah, maybe you would want to consider it, but if its first and last names then encrypting it would be overkill.
A common GetXMLString function might look like:
function GetPaymentXmlString() {
var xmlString = '';
xmlString = '<?xml version="1.0" encoding="UTF-8"?><Address><ZipCode>' + document.getElementById('txtbxZipCode').value + '</ZipCode></Address>';
return xmlString;
}
The important part of that function is to get your XML right. The first tag is pretty universal and should be fine to use in most situations and then after that its all just matching the tags up. I left out a lot of your fields to save space.
The last two function pointers are what you will want to call if everything goes as planned and if something fails respectively. The way that I normally handle successful requests is to hide the inputs as a whole(usually by putting them inside of their own div section) and displaying a confirmation message of some sort. Failed requests can be a bit trickier because you have to tell the user why they failed. The way that I do that is by having a dummy div section above everything else on the page with some sort of special CSS attached to it that makes the div stand out in some way and if the request fails then I send a string of text from the server with my best guess of why it failed and assign it to the be displayed in the div section. How you decide to display the results to the user is obviously all dictated by the project itself. Since what you do when it succeeds or fails is basically on a project by project basis I can't really give a good generic example of what you should do so for this part you are on your own.
Now that we have those pieces in place, the last piece to make is the handler.
Basically for all intents and purposes a handler is basically an ASPX webpage with nothing on it. So the HTML that makes up your handler pages, which have the extension .ashx, will look like:
<%# WebHandler Language="VB" CodeBehind="YourHandler.ashx.cs" Class="YourHandler" %>
And that's it. There should be no other markup in your actual .ashx file. Obviously the name of the handler will change depending on what you are doing.
The code behind when creating an ashx file by default will be a class that contains a single function named ProcessRequest. Basically you can treat this function as a sort of "request received" event. So in your case you would move the content of your btnSubmit_Click function to the ProcessRequest function in the ashx file. You can add any properties or other functions that you want but the ProcessRequest function must be present for the handler to work as far as I know.
One extra step that you will need to do is to get the information from the XML that was sent to your handler and also tell the response that you will be sending XML back to the client.
So to get the XML from the request you will need to do:
IO.StreamReader textReader = New IO.StreamReader(context.Request.InputStream);
context.Request.InputStream.Seek(0, IO.SeekOrigin.Begin);
textReader.DiscardBufferedData();
XDocument xml = XDocument.Load(textReader);
String zip = xml.Elements("Address").Elements("ZipCode").FirstOrDefault().Value;
In order to send XML back to the client you will need to add a couple headers to the response and you accomplish that by adding(I think this is the correct way to implement an interface in C# not positive on this point though):
class YourHandler : System.Web.IHttpHandler, System.Web.SessionState.IReadOnlySessionState
under your class definition and:
context.Response.ContentType = "text/xml";
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetAllowResponseInBrowserHistory(True);
to the beginning of your ProcessRequest function. Those six lines tell the client it will be receiving XML and not to cache any of the response which will ensure that your clients always see the most up-to-date content.
So. There it is. You should now have the framework to validate user input, create an AJAX request, send the request to a custom handler, accept XML from the client, write XML to the client and display the res-...I knew I forgot something...
What is the client supposed to do with the XML it gets from the server? throw it at the wall and see what sticks? No that won't work. You'll need a way to interpret the XML on the client side. Luckily the XMLHttpRequest object has been written to make this task a lot easier than it sounds.
You may have noticed that I set up my success and failure handlers to take a sender object and an XML object. The sender is really overkill and can be ignored(or removed) for this example to work fine. The XML object is what we are concerned with for now. Before we even get into the client side I must mention that you will have to go through the same process on the server side as you did on the client side and manually write your XML string including all the values you want the client to know about. For this example I'm going to assume you want to display a FriendlyMessage to the user. To write the response to the client you will do something like:
using (System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(context.Response.Output)) {
context.Response.AddHeader("Success", true);
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml("<?xml version='1.0' encoding='UTF-8'?><Response><FriendlyMessage>" + Message + "</FriendlyMessage></Response>");
doc.WriteTo(writer);
writer.Flush();
writer.Close();
}
On the client side to get the FriendlyMessage from the XML you will need to do:
xml.getElementsByTagName("FriendlyMessage")[0].childNodes[0].nodeValue
Now this line makes a few assumptions. Like, you may want to add some checks in to make sure xml.getElementsByTagName("FriendlyMessage") actually has children before trying to evaluate them. Those sorts of checks are up to your discretion.
This time I think I've actually covered all the steps. I hope my "little" guide helps you and I didn't bore you too much. I apologize for the length but its sort of a process so getting it right takes a few steps. Once you get the base line in place and working it really lends itself to any situation. This layout also makes your user experience much better than having them wait for full trips to the server each time.
I sincerely hope this helps you get your project done and that I haven't skipped a step or something equally as embarrassing...

Refreshing data using AJAX in ASP masterpage

I have some processes that run as a background job, allowing a user to continue to use a page, when the jobs are finished (which can take a few minutes) i want to display a message to the user, the best place to display this would be the masterpage AFAIK (incase they move from page to page on the site) so i have defined a div in the masterpage file.
I am trying to find the best method for displaying the data, at the moment i have a method in the masterpage vb file which polls a database to see if the job(which involves complex logic and some db access) has completed, if it has, it shows a message in the div e.g. "Job 13132 has completed" - which works fine.
The problem is this is not dynamic, and i have to refresh the page to call the function that checks if the processes have finished, how can i use AJAX to deliver this content automatically every 5 seconds?
I have tried using an asp timer with a 5 second tick time but the entire page refreshes on the timer click event every 5 seconds.
Protected Sub Timer1_Tick(Byval sender as Object, Byval e As EventArgs)
poll_results()
End Sub
Public Sub poll_results()
'database access logic
If dbtable.isCompleted = True
Dim sb As New StringBuilder()
sb.Append("$('#status').html('Job abc123 is complete');")
Page.ClientScript.RegisterStartupScript(GetType(Page), "myscript", sb.ToString(), True)
End If
End Sub
Is there a way to only refresh the div with the updated message, without a full refresh happening using this code? Or if this is not possible, is there any way to replicate the above function using jQuery and still be able to update the DIV text only if a job as finished?
You can easily go throw what we called, an async call, instead calling your method in the same page, just create an async folder in your website and add a new Generic Handler, call the page, for example checkPendingJobs.ashx.
in that page, add your current method:
Public Sub ProcessRequest (Byval context as HttpContext)
Dim r As String = ""
If dbtable.isCompleted = True
Dim sb As New StringBuilder()
r = "Job abc123 is complete"
End If
context.Response.ContentType = "text/plain"
context.Response.Write(r)
}
Now that you did your Server part, let's do the client part, in your page, add this jQuery code to tour masterpage, witch will fire every time some one refreshes the page, or you can use setInterval() to check it every xx seconds:
<script>
var checkJobs = true;
$(document).ready(function() {
// every time someone refreshes the page
checkPendingJobs();
// every 5 seconds...
setInterval(function(){ checkPendingJobs(); }, 5000);
});
function checkPendingJobs() {
// no need to check it if we already have a valid response
if(!checkJobs) return;
// caching issue trick
var now = new Date();
$.ajax({
url: "../async/checkPendingJobs.ashx",
type: "GET",
data: { t: now.getTime() },
success: function(data) {
// do we have text to show?
if(data.length > 0) {
alert(data);
checkJobs = false; // no need to check it more...
// $('#status').html(data);
}
},
error: function(msg) {
alert('Error found:\n' + msg);
}
});
}
</script>
The most common approach to this would be to create a single page that will render out either JSON or HTML. This of this as the "poll_results" method, think of it as poll_result.aspx. You can either pass a single Job ID to this page or just do a poll for any jobs that have finished since the last polling.
Your Masterpage will have a snipet of JavaScript that will use a timer (client side javascript timer) to send an AJAX request to the server, hitting your "poll_request.aspx" page. This page will return either HTML or JSON and you will write some JavaScript to show your message. If you need some code samples let me know.

jQuery UI autocomplete is not displaying results fetched via AJAX

I am trying to use the jQuery UI autocomplete feature in my web application. What I have set up is a page called SearchPreload.aspx. This page checks for a value (term) to come in along with another parameter. The page validates the values that are incoming, and then it pulls some data from the database and prints out a javascript array (ex: ["item1","item2"]) on the page. Code:
protected void Page_Load(object sender, EventArgs e)
{
string curVal;
string type ="";
if (Request.QueryString["term"] != null)
{
curVal = Request.QueryString["term"].ToString();
curVal = curVal.ToLower();
if (Request.QueryString["Type"] != null)
type = Request.QueryString["Type"].ToString();
SwitchType(type,curVal);
}
}
public string PreLoadStrings(List<string> PreLoadValues, string curVal)
{
StringBuilder sb = new StringBuilder();
if (PreLoadValues.Any())
{
sb.Append("[\"");
foreach (string str in PreLoadValues)
{
if (!string.IsNullOrEmpty(str))
{
if (str.ToLower().Contains(curVal))
sb.Append(str).Append("\",\"");
}
}
sb.Append("\"];");
Response.Write(sb.ToString());
return sb.ToString();
}
}
The db part is working fine and printing out the correct data on the screen of the page if I navigate to it via browser.
The jQuery ui autocomplete is written as follows:
$(".searchBox").autocomplete({
source: "SearchPreload.aspx?Type=rbChoice",
minLength: 1
});
Now if my understanding is correct, every time I type in the search box, it should act as a keypress and fire my source to limit the data correct? When I through a debug statement in SearchPreload.aspx code behind, it appears that the page is not being hit at all.
If I wrap the autocomplete function in a .keypress function, then I get into the search preload page but still I do not get any results. I just want to show the results under the search box just like the default functionality example on the jQuery website. What am I doing wrong?
autocomplete will NOT display suggestions if the JSON returned by the server is invalid. So copy the following URL (or the returned JSON data) and paste it on JSONLint. See if your JSON is valid.
http://yourwebsite.com/path/to/Searchpreload.aspx?Type=rbChoice&term=Something
PS: I do not see that you're calling the PreLoadStrings function. I hope this is normal.
A couple of things to check.
Make sure that the path to the page is correct. If you are at http://mysite.com/subfolder/PageWithAutoComplete.aspx, and your searchpreload.aspx page is in another directory such as http://mysite.com/anotherFolder/searchpreload.aspx the url that you are using as the source would be incorrect, it would need to be
source: "/anotherFolder/Searchpreload.aspx?Type=rbChoice"
One other thing that you could try is to make the method that you are calling a page method on the searchpreload.aspx page. Typically when working with javascript, I try to use page methods to handle ajax reqeusts and send back it's data. More on page methods can be found here: http://www.singingeels.com/Articles/Using_Page_Methods_in_ASPNET_AJAX.aspx
HTH.

Passing flash variables to asp.net

I don't know much about Flash but we are working on a site that has a flash form and when the users pick an option, like selecting a value from a drop down list, we need the value to be passed to asp.net server-side code. What's the easiest way to do this?
Flash can invoke server side service. So use GET or POST to pass data
You could explore these options:
1) Communicate between the SWF and the containing page through JavaScript
2) Communicate via asp.net webservices from the SWF directly to the webservice.
3) Not sure but could probably do a POST to a processing aspx page?
HTH
I think a good option is to use the XML class so consider this:
var xmlRequest = new XML();
xmlRequest.onLoad = parseXMLResponse;
xmlRequest.load("http://yourpathtoyourserver/file.aspx?listselectedvalue=something");
function parseXMLRequest(loaded)
{
trace("hi");
}
You can also have the page give you data back this way so it's not just one way communication.
Assuming you are using Action Script 2.
Read the important notes at the bottom of each codes pertain to sending and retrieving data from flash to .net page. Explanation of the code is in the comment inside the code.
Flash Part (Action Script 2)
//function to send collected form data to asp.net page
//use other control/button to call this function
//important: in order for the 'onLoad' event to work correctly, this function has to be 'Void'
function sendForm():Void
{
//create LoadVars object
var lv_in:LoadVars = new LoadVars();
var lv_out:LoadVars = new LoadVars();
//set onLoad event
lv_in.onLoad = function(success:Boolean)
{
//if success, meaning data has received from .net page, run this code
if (success)
{
//lv_in.status is use to get the posted data from .Net page
statusMsg.text = "Thank you for filling up the form!" + lv_in.status;
}
//if fail, run this code
else
{
statusMsg.text = "The form you are trying to fill up has an error!";
}
}
//this is the collected data from the form
lv_out.userName = txtUserName.text;
lv_out.userAddress = txtUserAddress.text;
lv_out.userBirthday = txtUserBirthday.text;
//begin invoke .net page
lv_out.sendAndLoad("ProcessDataForm.aspx", lv_in, "POST");
}
Important note:
The function that contain onLoad event, in this case sendForm function, has to be Void function, meaning it's not returning value. If this function return value, what happen is the function will be executed all the way without waiting for the returned data from .net page, thus the onLoad event will not be set properly.
.Net Part
public void ProcessData
{
//process the data here
Response.Write("status=processed&");
}
Important note:
To send data/message back to flash, you can use Response.Write. However, if you want Action Script to parse the posted message/data from .Net page keep in mind you have to include & symbol at the end of the message. When parsing data/message, Action Script will stop at & symbol, thus leave the rest of the message alone and only get the message under sent variable.

Resources