MVC SignalR keep increasing request count on each reload - javascript

I'm creating an ASP.NET MVC application which uses "SqlDependecy" and "SignalR" technologies to maintain real-time communication with the server based on database changes. It simply inspect a field value changes in specific database record and then display it on the browser.
The attempt works perfectly fine. But when I monitor the network requests through the browsers "Network" performance, the request count increases by 1 in every refresh of the page.
As in the image.
Initial page load only make one request.
First refresh after the initial load and then db change will lead to make 2 requests.
Second refresh after the initial load and then db change will lead to make 3 requests.
so on...
The js code I tried is given below.
It seams as an problem to me. If this is a real problem, Any advice on this will be highly appreciated. Thank you very much.
<script type="text/javascript">
$(function () {
var jHub = $.connection.journeyHub;
$.connection.hub.start();
jHub.client.ListenChange = function () {
getData();
}
jHub.client.ListenChange();
});
function getData() {
$.ajax({
url: 'GetValue',
type: 'GET',
dataType: 'json',
success: function (data) {
if (data == "pending") {
$("#box").css({ "background-color": "orange" });
}
else if (data == "deny") {
$("#box").css({ "background-color": "red" });
}
else if (data == "success") {
$("#box").css({ "background-color": "green" });
}
}
});
}
</script>
<div id="box" style="width:100px; height:100px; background-color: gray;"></div>
[Edit v1]
Here is my Controller where the event handler is located.
public class TravelController : Controller
{
SqlConnection link = new SqlConnection(ConfigurationManager.ConnectionStrings["linkTraveller"].ConnectionString);
// GET: Travel
public ActionResult Listen()
{
return View();
}
public ActionResult GetValue()
{
using (IDbConnection conn = link)
{
string query = #"SELECT [Status] FROM [dbo].[Journey] WHERE [Id]=1";
SqlCommand command = new SqlCommand(query, link);
SqlDependency sqlDep = new SqlDependency(command);
sqlDep.OnChange += new OnChangeEventHandler((sender, e) => sqlDep_OnChange(sender, e));
conn.Open();
string status = command.ExecuteScalar().ToString();
return Json(status, JsonRequestBehavior.AllowGet);
}
}
private void sqlDep_OnChange(object sender, SqlNotificationEventArgs e)
{
JourneyHub.Start();
}
}
Here is the Hub
public class JourneyHub : Hub
{
public static void Start()
{
var context = GlobalHost.ConnectionManager.GetHubContext<JourneyHub>();
context.Clients.All.ListenChange();
}
}

Off the top of my head, I would say you are not decrementing your trigger handlers, sql dependency triggers only fire once and then they are gone, you have to remember the remove the event handler for it or they just keep adding but, but I will know for sure if you can post your sql dependency trigger code.
Here is a sample from something I did many years ago, but the idea is still the same.
try
{
using (
var connection =
new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(#"SELECT [Id]
,[FName]
,[LName]
,[DOB]
,[Notes]
,[PendingReview]
FROM [dbo].[Users]",
connection))
{
// Make sure the command object does not already have
// a notification object associated with it.
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
command.ExecuteReader();
}
}
}
catch (Exception e)
{
throw;
}
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency dependency = sender as SqlDependency;
if (dependency != null) dependency.OnChange -= dependency_OnChange;
//Recall your SQLDependency setup method here.
SetupDependency();
JobHub.Show();
}

Related

Load a partial view (or more than one) after data is loaded in another

I have a script that renders a partial view after its data is loaded, but I want at least one other partial view to load using the same data. It's a long-running query (30sec - 1min), so I don't want to load it for each partial view. Or am I going down the wrong path? It should be noted I'm still pretty new to ASP.Net and very new to Javascript/Jquery, so I'm not totally aware of best practices, so if you spot something that's "against convention", please let me know that, too.
EDIT: It dawned on me I should note what I'm trying to eventually get to. In my current non-ASP app (C#/XAML), it loads the data (with an equivalent of LoadMonitorData method, below) when the app loads, then refreshes every 15 minutes. Or the refresh can be triggered by a Refresh button.
Here's what I've got so far...any help or guidance would be greatly appreciated.
Index.cshtml
#{
ViewBag.Title = "MMCView";
}
#section scripts {
<script type="text/javascript">
$(document).on('click', '[name^=project]', function () {
if ($(this).hasClass('selected')) {
$('.mig-project').removeClass('selected').removeClass('low-opacity').addClass('full-opacity');
$('#data-area').removeClass('show-data-view');
}
else {
$(this).addClass("selected").addClass('full-opacity').removeClass('low-opacity');
$('.mig-project').not(this).removeClass("full-opacity").removeClass('selected').addClass("low-opacity");
$('#data-area').load($(this).data("url"));
$('#data-area').addClass('show-data-view');
}
})
</script>
<script type="text/javascript">
$(document).ready(function(e) {
$("#list-container").each(function(index, item) {
var url = $(item).data("url");
if (url && url.length > 0) {
$(item).load(url);
}
})
})
</script>
}
<div class="project-list slow-load" id="list-container" data-url="/mmc/projectpanes">
<img src="loading.gif" />
</div>
<div class="hide-data-view slow-load" id="data-area" data-url="/mmc/projectdata"></div>
MMCController.cs
using MMC_ASP.Models;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using System.Web.Script.Serialization;
namespace MMC_ASP.Controllers
{
public class MMCController : AsyncController
{
MonitorData downloadedInfo = new MonitorData();
//GET: MMC
public ActionResult Index()
{
return View();
}
public ActionResult ProjectPanes()
{
downloadedInfo = LoadMonitorData();
return PartialView("_ProjectPanes", downloadedInfo.MainPanel.OrderBy(o => o.Client).ToList());
}
public ActionResult ProjectData(string server)
{
return PartialView("_ProjectData", downloadedInfo.Information.Where(x => x.ServerName == server).ToList());
}
public ActionResult MainWindowMonitor()
{
return PartialView("_MainWindowMonitor", downloadedInfo.MonitorText);
}
public MonitorData LoadMonitorData()
{
MonitorData deserializedData = null;
using (WebClient wc = new WebClient())
{
wc.Encoding = Encoding.Unicode;
string location = "http://MYWEBAPI-RETURNS-JSON";
string data = wc.DownloadString(new System.Uri(location));
var deserializer = new JavaScriptSerializer();
deserializedData = deserializer.Deserialize<MonitorData>(data);
}
return deserializedData;
}
}
}
In this situation, the Cache object might be useful to you. You can store your data in the Cache, set it to expire after a reasonable amount of time, write a helper function to re-pull the data on the fly if the cached data has expired, and have your partial views pull their data from the helper function. This way, the new data will only be pulled as needed, regardless how many views are using it, and as a bonus you have easy control over how often to re-execute that expensive query.
Note that this works well in your situation because your data is global in nature. If you were passing user-specific parameters into your query, then Cache wouldn't be a good fit.
using System.Web.Caching;
private MonitorData getCachedData()
{
var cache = this.HttpContext.Cache;
if (cache["MonitorData"] == null)
cache.Add("MonitorData", LoadMonitorData(), null, DateTime.Now.AddMinutes(15), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null); // 15 minute cache expiration, as example
return (MonitorData)cache["MonitorData"];
}
public ActionResult ProjectPanes()
{
downloadedInfo = getCachedData();
return PartialView("_ProjectPanes", downloadedInfo.MainPanel.OrderBy(o => o.Client).ToList());
}
public ActionResult ProjectData(string server)
{
downloadedInfo = getCachedData();
return PartialView("_ProjectData", downloadedInfo.Information.Where(x => x.ServerName == server).ToList());
}
public ActionResult MainWindowMonitor()
{
downloadedInfo = getCachedData();
return PartialView("_MainWindowMonitor", downloadedInfo.MonitorText);
}
The solution that Joe_Irby proposed works great! However, while communicating with him I found another approach that works as well. I figured I'd include it here so anyone else looking for a solution can decide which one will be best for their situation.
https://code.msdn.microsoft.com/Caching-In-Web-API-cb40be30

Sending SignalR alert messages from controller actions

I seem to have a problem sending an alert (toast) message from a controller action using SignalR. Unless I add a Thread.Sleep() after the send call, I never see the message. Inevitably, the send call occurs before return View(), so I imagine the alert is visible for a millisecond on the previous view, until the new one is served.
My first, rough solution is to use a timer to keep sending the message, until I get an acknowledgement.
This solution stinks. What else can I do? I can have the 'receiving' pages poll the server to see if they have any alerts, but that defeats the purpose of SignalR.
But then, maybe SignalR isn't suited to my case and I should just send the alerts as json strings on the model.
From the Login action:
....
//ModelState.AddModelError("", "Invalid login attempt.");
AlertsHub.ShowClientAlert(new Alert(AlertLevel.Error, "Invalid login attempt."));
return View(model);
The hub:
public class AlertsHub : Hub
{
private static Alert pendingAlert;
static Timer pollTimer;
internal static void ShowClientAlert(Alert alert)
{
if (pendingAlert != null)
{
return;
}
pendingAlert = alert;
pollTimer = new Timer(_ => SendAlert(pendingAlert), null, 0, 500);
}
static private void SendAlert(Alert alert)
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<AlertsHub>();
context.Clients.All.ShowAlert(alert.Level.ToString(), alert.Message, alert.Title);
}
[HubMethodName("AlertReceived")]
public void AlertReceived(Guid alertId)
{
pollTimer.Dispose();
pendingAlert = null;
}
}
From the JS:
var toast;
$(function () {
if (typeof toast != 'undefined' && toast != null) {
showToast(toast);
toast = null;
}
var alertsProxy = $.connection.alertsHub;
alertsProxy.client.showAlert = function(alertId, level, message, title) {
toast.alertId = alertId;
toast.level = level;
toast.message = message;
toast.title = title;
};
$.connection.hub.start()
.done(function () {
console.log('Now connected, connection ID=' + $.connection.hub.id);
})
.fail(function () {
console.log('Could not Connect!');
});
});
function showToast(toast) {
switch (toast.level.toLowerCase()) {
case "success":
toastr.success(toast.message, toast.title);
break;
...
}
alertsProxy.server.AlertReceived(alertId)
.done(function() {
console.log("Alert '" + alertId + "' acknowledged.");
})
.fail(function() {
console.log("Acknowledgement of alert '" + alertId + "' failed.");
});
}

Client always responding to previous server-sent event, not current event

I am seeing odd behavior with the code here.
Client-side (Javascript):
<input type="text" id="userid" placeholder="UserID" /><br />
<input type="button" id="ping" value="Ping" />
<script>
var es = new EventSource('/home/message');
es.onmessage = function (e) {
console.log(e.data);
};
es.onerror = function () {
console.log(arguments);
};
$(function () {
$('#ping').on('click', function () {
$.post('/home/ping', {
UserID: parseInt($('#userid').val()) || 0
});
});
});
</script>
Server-side (C#):
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Web.Mvc;
using Newtonsoft.Json;
namespace EventSourceTest2.Controllers {
public class PingData {
public int UserID { get; set; }
public DateTime Date { get; set; } = DateTime.Now;
}
public class HomeController : Controller {
public ActionResult Index() {
return View();
}
static ConcurrentQueue<PingData> pings = new ConcurrentQueue<PingData>();
public void Ping(int userID) {
pings.Enqueue(new PingData { UserID = userID });
}
public void Message() {
Response.ContentType = "text/event-stream";
do {
PingData nextPing;
if (pings.TryDequeue(out nextPing)) {
var msg = "data:" + JsonConvert.SerializeObject(nextPing, Formatting.None) + "\n\n";
Response.Write(msg);
}
Response.Flush();
Thread.Sleep(1000);
} while (true);
}
}
}
Once I've pressed ping to add a new item to the pings queue, the loop inside the Message method picks the new item up and issues an event, via Response.Write (confirmed using Debug.Print on the server). However, the browser doesn't trigger onmessage until I press ping a second time, and the browser issues another event; at which point the data from the first event reaches onmessage.
How can I fix this?
To clarify, this is the behavior I would expect:
Client Server
-------------------------------------------------------------------
Press Ping button
XHR to /home/ping
Eneque new item to pings
Message loop issues server-sent event
EventSource calls onmessage
This is what is actually happening:
Client Server
-------------------------------------------------------------------
Press Ping button
XHR to /home/ping
Eneque new item to pings
Message loop issues server-sent event
(Nothing happens)
Press Ping button again
New XHR to /home/ping
EventSource calls onmessage with previous event data
(While running in Chrome the message request is listed in the Network tab as always pending. I'm not sure if this is the normal behavior of server-sent events, or perhaps it's related to the issue.)
Edit
The string representation of the msg variable after Response.Write looks like this:
"data:{\"UserID\":105,\"Date\":\"2016-03-11T04:20:24.1854996+02:00\"}\n\n"
very clearly including the newlines.
This isn't an answer per say but hopefully it will lead one. I was able to get it working with the following code.
public void Ping(int id)
{
pings.Enqueue(new PingData { ID = id });
Response.ContentType = "text/plain";
Response.Write("id received");
}
public void Message()
{
int count = 0;
Response.ContentType = "text/event-stream";
do {
PingData nextPing;
if (pings.TryDequeue(out nextPing)) {
Response.ClearContent();
Response.Write("data:" + nextPing.ID.ToString() + " - " + nextPing.Date.ToLongTimeString() + "\n\n");
Response.Write("event:time" + "\n" + "data:" + DateTime.Now.ToLongTimeString() + "\n\n");
count = 0;
Response.Flush();
}
if (!Response.IsClientConnected){break;}
Thread.Sleep(1000);
count++;
} while (count < 30); //end after 30 seconds of no pings
}
The line of code that makes the difference is the second Response.Write. The message doesn't appear in the browser until the next ping similar to your issue, but the ping always appears. Without that line the ping will appear only after the next ping, or once my 30 second counter runs out.
The missing message appearing after the 30 second timer leads me to conclude that this is either a .Net issue, or there's something we're missing. It doesn't seem to be an event source issue because the message appears on a server event, and I've had no trouble doing SSE with PHP.
For reference, here's the JavaScript and HTML I used to test with.
<input type="text" id="pingid" placeholder="ID" /><br />
<input type="button" id="ping" value="Ping" />
<div id="timeresponse"></div>
<div id="pingresponse"></div>
<script>
var es = new EventSource('/Home/Message');
es.onmessage = function (e) {
console.log(e.data);
document.getElementById('pingresponse').innerHTML += e.data + " - onmessage<br/>";
};
es.addEventListener("ping", function (e) {
console.log(e.data);
document.getElementById('pingresponse').innerHTML += e.data + " - onping<br/>";
}, false);
es.addEventListener("time", function (e) {
document.getElementById('timeresponse').innerHTML = e.data;
}, false);
es.onerror = function () {
console.log(arguments);
console.log("event source closed");
es.close();
};
window.onload = function(){
document.getElementById('ping').onclick = function () {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function () {
console.log(this.responseText);
};
var url = '/Home/Ping?id=' + document.getElementById('pingid').value;
xmlhttp.open("GET", url);
xmlhttp.send();
};
};
</script>
Since an eventstream is just text data, missing the double line break before the first event is written to response could affect the client. The example from mdn docs suggests
header("Content-Type: text/event-stream\n\n");
Which could be applied apply to .NET response handling (note the side effects of Response.ClearContent()).
If it feels too hacky, you could start your stream with a keep-alive comment (if you want to avoid timing out you may have to send comments periodically):
: just a keep-alive comment followed by two line-breaks, Response.Write me first
I'm not sure if this will work because I can't try it now, but what about to add an End?:
Response.Flush();
Response.End();
The default behavior of .net is to serialize access to session state. It blocks parallel execution. Requests are processed sequentially and access to session state is exclusive for the session. You can override the default state per class.
[SessionState(SessionStateBehavior.Disabled)]
public class MyPulsingController
{
}
There is an illustration of this in the question here.
EDIT: Would you please try creating the object first and then passing it to Enqueue? As in:
PingData myData = new PingData { UserID = userID };
pings.Enqueue(myData);
There might be something strange going on where Dequeue thinks it's done the job but the the PingData object isn't properly constructed yet.
Also can we try console.log("I made it to the function") instead of console.log(e.data).
---- PREVIOUS INFORMATION REQUESTED BELOW ----
Please make sure that the server Debug.Print confirms this line of code:
Response.Write("data:" + JsonConvert.SerializeObject(nextPing, Formatting.None) + "\n\n");
Is actually executed? Please double check this. If you can capture the server sent response then can we see what it is?
Also could we see what browsers you've tested on? Not all browsers support server events.

When is the connection closed with SignalR from browser

I'm making a little chat application with SignalR 2.0 (just like everyone).
I have a win8.1 application and when the application is closed, the hub receives the OnDisconnected event and removes the user from the list on the hub.
The hub sends to every client that the user has left the chat, so we can visualize that the user has left.
But when I'm using SignalR and Javascript in a webpage and the page gets closed, the hub doesn't get notified that the tab/browser is closed...
Anyone any idea how the connection can be closed?
What i've coded:
Startup Hub
[assembly: OwinStartup(typeof(ChatServer.Startup))]
namespace ChatServer
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Map all hubs to "/signalr"
app.MapSignalR();
}
}
}
Hub
[HubName("ChatHub")]
public class ChatHub : Hub
{
private static List<User> Users = new List<User>();
public void Send(string name, string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(name, message, DateTime.Now);
}
public void UserConnected(string name)
{
Clients.Caller.connected(JsonConvert.SerializeObject(Users));
User user = new User() { Name = name, ConnectionID = Context.ConnectionId };
Clients.Others.userConnected(JsonConvert.SerializeObject(user));
Users.Add(user);
}
public void UserLeft()
{
if(Users.Any(x=>x.ConnectionID == Context.ConnectionId))
{
User user = Users.First(x => x.ConnectionID == Context.ConnectionId);
Users.Remove(user);
Clients.Others.userLeft(JsonConvert.SerializeObject(user), Context.ConnectionId);
}
}
public override System.Threading.Tasks.Task OnDisconnected()
{
// Only called when win8.1 app closes
// Not called when browsers closes page
UserLeft();
return base.OnDisconnected();
}
}
HTML - Javascript:
Javascript:
chat = new function () {
var ChatHub;
// Connecting to the hub
this.attachEvents = function () {
if ($.connection != null) {
ChatHub = $.connection.ChatHub;
$.connection.hub.start({ transport: 'auto' }, function () {
// Register client on hub
ChatHub.server.userConnected("web name");
});
}
this.send = function (name,message) {
if ($.connection != null) {
//Send chat message
ChatHub.server.send(name, message).fail(function (e) {
alert(e);
});
}
}
}
};
window.onbeforeunload = function (e) {
//This is called when we close the page
$.connection.hub.stop();
return "You killed me! :'(";
};
Win8.1 client
internal async void ConnectToHub(string userName)
{
try
{
HubConnection hubConnection = new HubConnection(SERVER_PROXY);
chat = hubConnection.CreateHubProxy("ChatHub");
Context = SynchronizationContext.Current;
MakeHubFunctionsAvailableOnClient();
await hubConnection.Start();
// Register client on hub
await chat.Invoke("UserConnected", userName);
}
catch (Exception)
{
throw;
}
}
private void MakeHubFunctionsAvailableOnClient()
{
//Receive chat messages
chat.On<string, string, DateTime>("broadcastMessage",
(name, message, date) => Context.Post(
delegate {
Messages.Add(new UserMessage() { Message = message, User = name, Date = date });
}, null
)
);
//Receive all online users
chat.On<string>("connected",
(users) => Context.Post(
delegate
{
List<User> userList = JsonConvert.DeserializeObject<List<User>>(users);
foreach (User user in userList)
{
Users.Add(user);
}
Messages.Add(new UserMessage() { Message = "CONNECTED", User = "System", Date = DateTime.Now });
}, null
)
);
//New user connected
chat.On<string>("userConnected",
(user) => Context.Post(
delegate
{
User newUser = JsonConvert.DeserializeObject<User>(user);
Users.Add(newUser);
Messages.Add(new UserMessage() { Message = newUser.Name + " CONNECTED", User = "System", Date = DateTime.Now });
}, null
)
);
//User left, remove user from list on client
chat.On<string>("userLeft",
(user) => Context.Post(
delegate
{
User newUser = JsonConvert.DeserializeObject<User>(user);
User y = Users.First(x=>x.ConnectionID == newUser.ConnectionID);
bool ux = Users.Remove(y);
Messages.Add(new UserMessage() { Message = newUser.Name + " left the conversation", User = "System", Date = DateTime.Now });
}, null
)
);
}
My hub doesn't trigger OnDisconnected, when i close tab / browser / navigating to other site
The site is a singe page website (for the moment)
What browser am i using? Chrome: Version 32.0.1700.68 beta-m
Internet Explorer 11
I guess your question is how to detect whether a specific user left or closed the browser. When a user comes in or leaves, send a notification to other users.
I think the problem is you didn't handle OnConnected and OnDisconnected properly.
To make it work, first you need to know each client connecting to a hub passes a unique connection id. You can retrieve this value in the Context.ConnectionId property of the hub context. When each client comes in, they go through OnConnected, when they leave, they go through OnDisconnected. Below is a working example:
Hub Class
[HubName("ChatHub")]
public class ChatHub : Hub
{
private static List<User> Users = new List<User>();
public void Send(string message)
{
var name = Context.User.Identity.Name;
Clients.All.broadcastMessage(name, message, DateTime.Now.ToShortDateString());
}
public override Task OnConnected()
{
User user = new User() { Name = Context.User.Identity.Name, ConnectionID = Context.ConnectionId };
Users.Add(user);
Clients.Others.userConnected(user.Name);
return base.OnConnected();
}
public override Task OnDisconnected()
{
if (Users.Any(x => x.ConnectionID == Context.ConnectionId))
{
User user = Users.First(x => x.ConnectionID == Context.ConnectionId);
Clients.Others.userLeft(user.Name);
Users.Remove(user);
}
return base.OnDisconnected();
}
}
View
<input type="text" id="message" />
<button class="btn">Send</button>
<ul id="contents"></ul>
#section scripts
{
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.signalR-2.0.1.js"></script>
<script src="/signalr/hubs"></script>
<script>
var chatHub = $.connection.ChatHub;
chatHub.client.broadcastMessage = function (name, message, time) {
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
var encodedTime = $('<div />').text(time).html();
$('#contents').append('<li><strong>' + encodedName + '</strong>: ' + encodedMsg + '</strong>: ' + encodedTime + '</li>');
};
chatHub.client.userConnected = function (data) {
$('#contents').append('<li>Wellcome<strong>' + '</strong>:' + data + '</li>');
};
chatHub.client.userLeft = function (data) {
$('#contents').append('<li>Bye<strong>' + '</strong>:' + data + '</li>');
};
$(".btn").on("click", function() {
chatHub.server.send($("#message").val());
});
$.connection.hub.start().done(function() {
console.log("connected...");
});
</script>
}
You might be running into the issue described here: https://github.com/SignalR/SignalR/issues/2719
tl;dr: There is a bug introduced in Chrome 31 that is already fixed in Chrome Canary, that prevents SignalR from immediately trigger OnDisconnected.
If you are, you can use the workaround I suggested in the issue which is to add the following to your JS code.
window.onbeforeunload = function (e) {
$.connection.hub.stop();
};
Even with this bug and without the workaround I would expect SignalR to raise OnDisconnected approximately 35s after the browser exits the page hosting SignalR.
Can you provide more details about which browsers you are experiencing this issue with and in what situations? (e.g. closing the tab, closing the window, refreshing, navigating to another page on the same site, navigating to a different site, etc.)

Uploadify response value is always undefined from ASP.NET

I'm using Uploadify to upload some images with ASP.NET.
I use Response.WriteFile() in ASP.NET to return the result of the upload back to JavaScript.
As specified in the documentation I'm using onAllComplete event to check for response string from ASP.NET.
The problem is it that the alert(response); is always undefined in JavaScript.
JavaScript code as below:
$(document).ready(function() {
var auth = "<% = Request.Cookies[FormsAuthentication.FormsCookieName]==null ? string.Empty : Request.Cookies[FormsAuthentication.FormsCookieName].Value %>";
$('#btnUpdateProfileImg').uploadify({
'uploader': '../script/uploadify/uploadify.swf',
'script': '../uploadprofimg.aspx',
'cancelImg': '../script/uploadify/cancel.png',
'folder': '../script/uploadify',
'scriptData': { 'id': $(this).attr("id"), 'token': auth },
'onAllComplete': function(event, queueID, fileObj, response, data) {
alert(response);
}
});
});
ASP.NET code a below;
protected void Page_Load(object sender, EventArgs e)
{
try
{
string token = Request.Form["token"].ToString();
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(token);
if (ticket != null)
{
var identity = new FormsIdentity(ticket);
if (identity.IsAuthenticated)
{
HttpPostedFile hpFile = Request.Files["ProfileImage"];
string appPath = HttpContext.Current.Request.ApplicationPath;
string fullPath = HttpContext.Current.Request.MapPath(appPath) + #"\avatar\";
hpFile.SaveAs(Server.MapPath("~/" + uniqName));
Response.ContentType = "text/plain";
Response.Write("test");
}
}
}
catch (Exception ex)
{
Response.Write("test");
}
}
Reason for the FormsAuthenticationTicket object is to pass the authentication cookie though when using the Uploadify with Firefox.
I have seen many examples where Response.Write returns a value back to the onAllComplete event. But all I get is undefined.
I have also tried to use Context.Response.Write, this.Response.Write, HttpContext.Current.Response.Write. They all return undefined.
Any help appreciated.
Thanks
It seems that the onAllComplete event never fires. This is possibly because I'm automatically uploading single files rather than multiple files.
I find that the onComplete event fires and I can use that instead.

Categories

Resources