ASP.NET UpdatePanel cause full postback after idle - asp.net

I'm using multiple updatepanels in my SharePoint Visual Web Parts. Everything is working fine until I leave the page to idle for a while.
For example if I change a few drop downs and leave the page to idle for about 5 minutes. Coming back to the page and changing a drop down will cause a full postback.
Another example is using a gridview with pagination. Leaving the grid view on page 5. Idle for 5 minutes and come back to the page. Clicking on page 8 for example will make the gridview go to page 1.
I am new to using Updatepanels and would really appreciate some advice.

I have solver this anonymous problem by adding this javascript. I have found that after some ideal time(~30sec) for each request it page goes for authenticate user. and if user is not authentication then it reload the whole page and re authenticate user that's why page is reload.
Add this java script code in your page which will solve your problem.
<script type="text/javascript">
var isNtlmActive = false;
var updatePannelsToUpdate = [];
var eventTarget = '';
var eventArgument = '';
var causesValidation = false;
var validationGroup = '';
var requestBody = '';
function initializeRequestHandler(sender, args) {
var onSuccess = function () {
//At this point the NTLM connection is re-established
var pageRequestManagerInstance;
isNtlmActive = true;
pageRequestManagerInstance = Sys.WebForms.PageRequestManager.getInstance();
// re-issuing the 'original' request
pageRequestManagerInstance.beginAsyncPostBack(updatePannelsToUpdate, eventTarget, eventArgument, causesValidation, validationGroup);
};
var onError = function () {
// do something here if error occurred
}
if (!isNtlmActive) {
// capturing and preserving the body as well as some other meta data about the original request
requestBody = args.get_request().get_body();
updatePannelsToUpdate = sender._postBackSettings.panelsToUpdate;
eventTarget = sender._postBackSettings.asyncTarget;
eventArgument = '';
causesValidation = false;
validationGroup = '';
// NOTE: the variable '_spFormOnSubmitCalled' is a global variable that gets injected by the logic iplemented in the 'init.js' file.
// Based on our observation of the logic in 'init.js' the varialbe '_spFormOnSubmitCalled' is set to true when HTML form's
// 'onsubmit' function is called and it is never set back to false (after we cancel the postback)
// As the result, any subsequent attempts to submit the form do not work.
// Thus, we excplicetely set the value back to false before we cancel the original post back request.
//
//'init.js'is autoatically referenced by SharePoint and included on to the 'master' page.
// The HTML form as well as the functionality to handle submit is also provided by SharePoint.
if (typeof _spFormOnSubmitCalled === "boolean") {
_spFormOnSubmitCalled = false;
}
args.set_cancel(true);
callServerSideServiceToReviveNtlmSession(onSuccess, onError);
}
else {
// resetting the body of the request with the value captured from the original request
args.get_request().set_body(requestBody);
isNtlmActive = false;
updatePannelsToUpdate = [];
eventTarget = '';
eventArgument = '';
causesValidation = false;
validationGroup = '';
}
}
function getCurrentSiteCollectionUrl() {
var url;
url = window.location.protocol + "//" + window.location.host + _spPageContextInfo.siteServerRelativeUrl;
return url;
}
function callServerSideServiceToReviveNtlmSession(successHandler, errorHandler) {
var siteCollectionUrl;
var testServiceUrl;
var spRequestExecutor;
var request;
siteCollectionUrl = getCurrentSiteCollectionUrl();
testServiceUrl = siteCollectionUrl + "/_api/web/title";
spRequestExecutor = new SP.RequestExecutor(siteCollectionUrl);
request = {
url: testServiceUrl,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: successHandler,
error: errorHandler
};
spRequestExecutor.executeAsync(request);
}
try {
$(document).ready(function () {
try {
var pageRequestManagerInstance = null;
//Note: Sys.WebForms.PageRequestManager gets injected into your page the minute you use ScriptManager (and UpdatePanel)
pageRequestManagerInstance = Sys.WebForms.PageRequestManager.getInstance();
pageRequestManagerInstance.add_initializeRequest(initializeRequestHandler);
}
catch (ex) {
//alert('INNER EXCEPTION: document ready - ' + ex.message);
}
});
}
catch (ex) {
//alert('EXCEPTION: document ready - ' + ex.message);
}
</script>
Mark as answer if this answer found helpful...
Thanks..!!

Enable or disable session state across the entire farm
On the taskbar, click Start, point to Administrative Tools, and then click SharePoint 3.0 Central Administration.
In the top navigation bar, click the Application Management tab.
On the Application Management page, in the Office SharePoint Servers Shared Services section, click Configure session state.
On the Configure Session State page, in the Enable Session State section, select the Enable Session State check box to enable session state for the farm.
To specify the duration of sessions, in the Timeout section, enter a number (in minutes) in the Session should be timed out after (minutes) box. The default is 60 minutes.
Click OK to save the session state configuration.
This one will give you more guidance
http://technet.microsoft.com/en-us/library/cc263527.aspx
if any confusion ask me,

Related

How to have "Request" events with authenticated user id?

I have instrumented my web application to have telemetry events sent to azure portails with the authenticated user id when available.
It works for TrackEvent coming from backend : for that once my user is authenticated , I add some information in the HttpContext.Current.Session that I am using in the TelemetryInitialiser.
public class MyTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
if (HttpContext.Current?.Session?["user"] != null)
{
// Set the user id on the Application Insights telemetry item.
telemetry.Context.User.AuthenticatedUserId = user;
telemetry.Context.User.UserAgent = HttpContext.Current.Request.UserAgent;
// Set the session id on the Application Insights telemetry item.
telemetry.Context.Session.Id = HttpContext.Current.Session.SessionID;
}
}
}
and in Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
BundleTable.EnableOptimizations = false;
AutoMapperConfig.RegisterMappings();
Bootstrapper.Initialise();
TelemetryConfiguration.Active.TelemetryInitializers.Add(new Common.MyTelemetryInitializer());
}
}
This makes already all events coming from back-end having the authenticated id
field set ( namely : Trace, Custom Event, Exception , Dependency (call to DB ).
After that I also customized the automatically created Javascript code in the Front End so that "Page View" have as well the authenticated id :
<script type='text/javascript'>
var appInsights=window.appInsights||function(config)
{
function r(config){ t[config] = function(){ var i = arguments; t.queue.push(function(){ t[config].apply(t, i)})} }
var t = { config:config},u=document,e=window,o='script',s=u.createElement(o),i,f;for(s.src=config.url||'//az416426.vo.msecnd.net/scripts/a/ai.0.js',u.getElementsByTagName(o)[0].parentNode.appendChild(s),t.cookie=u.cookie,t.queue=[],i=['Event','Exception','Metric','PageView','Trace','Ajax'];i.length;)r('track'+i.pop());return r('setAuthenticatedUserContext'),r('clearAuthenticatedUserContext'),config.disableExceptionTracking||(i='onerror',r('_'+i),f=e[i],e[i]=function(config, r, u, e, o) { var s = f && f(config, r, u, e, o); return s !== !0 && t['_' + i](config, r, u, e, o),s}),t
}({
instrumentationKey:'XXXXXXXXXXXXXXXXXX'
});
window.appInsights=appInsights;
</script>
#if (Request.IsAuthenticated)
{
<script>
var user = "#User.Identity.Name.Replace("\\", "\\\\")";
appInsights.setAuthenticatedUserContext(user.replace(/[,;=| ]+/g, "_"));
</script>
}
<script>
appInsights.trackPageView();
</script>
For that to work it supposes that I set a Response Cookie before when authentified in the back end.
This is also working and I have my Page View events with the authenticated user id.
Nevertheless, I still have a gap : Request event does no have the authenticated user id field set.
If I examine the Requests without the field, it is both Direct Requests and all the AJAX requests that can be triggered when browsing a page. (some Going to Application defined pages, others part of the framework)
This time I have no idea of how can I make them contained the authenticated user. Any help appreciated.

SignalR - correct implementation of chat

I need to implement chat on my web project. How to implement it on one page - there are many articles about it. But I need to have ability :
1. Notify other users, that somebody logged to site (on any page, not only on chat page)
2. Notify other users, that somebody logout
So, I have the following code of hub:
public void Connect()
{
try
{
var id = Context.ConnectionId;
string username = Context.User.Identity.Name;
var currentUser = connectedUsers.Where(p => p.Username == username).FirstOrDefault();
if (currentUser == null)
{
AddNewUserToCollection();
}
else
{
// update ConnectionId for sure (connection id is changed sometimes (probably if user is logged out and login again))
if (currentUser.ConnectionId != id)
{
var companyId = _chatRepository.GetCompanyIdOfUser(username); // throws exception if companyId is null
Groups.Remove(currentUser.ConnectionId, companyId.ToString());
Groups.Add(id, companyId.ToString());
currentUser.ConnectionId = id;
//Clients.Group(companyId.ToString()).onNewUserConnected(username);
}
}
}
catch(InvalidCompanyException c_ex)
{
Clients.Client(Context.ConnectionId).onErrorMessage($"User '{c_ex.Username}' does not exist");
}
}
public void Disconnect()
{
string username = Context.User.Identity.Name;
var item = connectedUsers.Where(p => p.Username == username).FirstOrDefault();
if (item != null)
{
connectedUsers.Remove(item);
Groups.Remove(item.ConnectionId, item.CompanyID.ToString());
Clients.Group(item.CompanyID.ToString()).onUserDisconnected(item.Username);
}
}
public override Task OnDisconnected(bool stopCalled)
{
var item = connectedUsers.Where(p => p.ConnectionId == Context.ConnectionId).FirstOrDefault();
if (item != null)
{
connectedUsers.Remove(item);
Groups.Remove(item.ConnectionId, item.CompanyID.ToString());
Clients.Group(item.CompanyID.ToString()).onUserDisconnected(item.Username);
}
return base.OnDisconnected(stopCalled);
}
and I added the following code to _layout.cshtml:
<script>
$(document).ready(function () {
var chat = $.connection.chatHub;
$.connection.hub.start().done(function () {
chat.server.connect();
});
});
</script>
to notify other users, that the current user is logged. But debugger says, that pair OnDisconnected/Connect is called every time, when user reload page (go thru pages) with different connectionId. When I remove this client code - that pair is not called. How to implement it correctly, to notify other users, that somebody is online, but without reconnect each time?
Since you have the connect() call in a razor (_layout.cshtml) page, you will effectively be disconnecting/connecting on every post back (page load).
The scenario you're trying to use is best in a SPA (or AJAX) scenario where navigation is handled asynchronously by client side JavaScript. Your current setup is refreshing the screen, reloading the JavaScript, re-running the document ready() function with each server rendered navigation.
Another alternative is to use the client's actual user Id, and pass that to the server.connect(id) method. Then use this user Id to track the user activity instead of the hub ConnectionId.

.Net Server-Sent Events using HttpHandler not working

I have been trying to implement an event driven push to a client browser. I am using ReactiveX to produce the async task from the events but I can't even get my HttpHandlers to output their response.
I have tried with a simple HttpHandler:
public class Handler2 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/event-stream";
HttpResponse response = context.Response;
DateTime startdate = DateTime.Now;
while (startdate.AddMinutes(10) > DateTime.Now)
{
JavaScriptSerializer js = new JavaScriptSerializer();
string responseText = DateTime.Now.TimeOfDay.ToString();
response.Write(string.Format("data: {0}",js.Serialize(responseText)));
response.Flush();
System.Threading.Thread.Sleep(1000);
}
response.Close();
}
public bool IsReusable
{
get
{
return false;
}
}
}
with the following client side code:
function initialize() {
if (window.EventSource == undefined) {
document.getElementById('targetDiv').innerHTML = "Your browser doesn't support Server Side Events.";
return;
}
var source = new EventSource('Handler2.ashx');
source.onopen = function (event) {
document.getElementById('targetDiv').innerHTML += 'Connection Opened.<br>';
};
source.onerror = function (event) {
if (event.eventPhase == EventSource.CLOSED) {
document.getElementById('targetDiv').innerHTML += 'Connection Closed.<br>';
}
};
source.onmessage = function (event) {
document.getElementById('targetDiv').innerHTML += event.data + '<br>';
};
}
I have more a more complex HttpTaskAsyncHandler ready to hook up, but I can't even get this working >_<
I get the Connection Opened message, Handler2.ashx appears to remain connected (Looking at Chrome dev tools / Network).
I am, on the other hand, getting some data from a SignalR connection?
"ws://localhost:50022/ed4b66c7eb394a8789b5f6a631f4ff09/arterySignalR/connect?.."
Have I set it up wrong?
As far as I've seen on other examples, this code should be working as-is. Please could anyone help me. I just want a simple SSE control that I can trigger from server side events.
Thanks in advance
I had given this answer before, but let me elaborate:
Looking at the Network tab in Google Chrome developer tools reveals quite a lot from your http://live.meetscoresonline.com/test-sse.aspx
There are no SSE being generated at all - to see this click on the Others button under Network, this is where you would normally be able to track the SSE data stream
I use the following code in my SSE's with a simple HTTPListener and it works well without the delays you mentioned, and always shows up correctly across browsers when using this polyfill
res.AddHeader("Content-Type", "text/event-stream")
res.AddHeader("Cache-Control", "no-cache")
res.AddHeader("Access-Control-Allow-Origin", "*")
res.KeepAlive = True

ASP.NET MVC determine remaining session timeout using SessionState

In one of my web application I need to popup alert when session timeout in 5 minutes. Users have option either continue to extend the session or log out immediately.
In Web.config set session timeout to 30 min:
<sessionState mode="InProc" timeout="30">
Since ASP.NET MVC do not give a way to check the remaining session timeout, I come up a solution as follow:
In Global.asax it tracks the current session last access time as a session variable. If the coming in request is not session state readonly (see below), the last access time session variable is updated with current time. Otherwise session variable's value is set with current time.
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
var context = HttpContext.Current;
if (context != null && context.Session != null && !context.Session.IsReadOnly)
{
context.Session["_LastAccessTime"] = DateTime.Now;
}
}
In my session controller, I set the session state behavior to read only. Requests to this controller neither reset session nor do it refresh my last access time session variable.
[SessionState(SessionStateBehavior.ReadOnly)]
public class SessionController : BaseController
{
[AjaxOnly]
public ActionResult GetRemainingSessionTimeout()
{
if (!Request.IsAjaxRequest())
{
return Content("Not an Ajax call.");
}
var remainingSessionTimeout = 0;
if (Session["_LastAccessTime"] != null)
{
var lastAccessTime = (DateTime) Session["_LastAccessTime"];
var timeSpan = DateTime.Now.Subtract(lastAccessTime);
remainingSessionTimeout = Session.Timeout - timeSpan.Minutes;
}
return Json(new {RemainingSessionTimeout = remainingSessionTimeout}, JsonRequestBehavior.AllowGet);
}
}
In a view, Ajax request checks the remaining session timeout silently. If less than 5 min, then popup alert:
$(document).ready(function () {
$("#remainingSessionTimeout").click(function (e) {
var url = '#Url.Action("GetRemainingSessionTimeout", "Session", new { area = "" })';
$.ajax({
type: "POST",
url: url,
data: {},
success: function (result) {
$("#timeoutLeft").html('Your session expries in ' + result.Timeout * 60 + ' seconds.');
},
error: function (result) {
$("#timeoutLeft").html('error in getting session data.');
}
});
});
});
Any drawback or flaw of this solution? Thanks.

open a new window of view when call controller from Jquery Ajax post call

I'm using ASP.Net MVC2. I'm trying to open a new window of view when call controller from Jquery Ajax post call.
here is my code..
in ascx page..
$('#DeleteButton').click(function () {
var isLineChecked = $(':checkbox:checked', '#providerSearchResultsTable').length;
if (isLineChecked == 0) {
alert("Please select at least one row ");
return false;
}
else {
var params = {
Id: gaiSelected.join(',')
};
alert(params);
$.ajax({
type: "Post",
url: "SelectProviderAndContact",
data: params,
success: function (html) {
**//$('#SelectProviderAndContact').html(html);**
}
});
}
});
here is my controller Action method
[SessionFilter]
public ActionResult SelectProviderAndContact(string Id)
{
try
{
List<ProviderBaseInfo> providerList = null;
string[] internalProviderIDs = Id.Split(",".ToCharArray());
//string[] billingProviderNames = billingProvider.Split(",".ToCharArray());
IStateBag stateBag = _commonModel.GetStateBag();
//stateBag.SetValue("InternalProviderId", Id);
List<Guid> internalProviderIds = new List<Guid>();
foreach (var a in internalProviderIDs)
{
internalProviderIds.Add(new Guid(a));
}
List<Contacts> providerContactList = _providerModel.GetProviderContactlist(internalProviderIds);
if (providerContactList.Count <= 0)
{
//IStateBag stateBag = GetStateBag();
List<ProviderBaseInfo> providers = (List<ProviderBaseInfo>)stateBag.GetValue(ProviderListCache);
if (providers == null)
{
providerList = _providerModel.GetProviderCompleteList(null, null, null, null, Id).ToList();
}
else
{
providerList = providers.Where(x => internalProviderIds.Contains(x.InternalProviderId)).ToList();
}
providerContactList = _providerModel.GetContactlistbyInsertingProviders(providerList);
}
ViewData["ProviderNotFound"] = false;
// ViewData["ProviderName"] = new SelectList(billingProvider.Select(x => new { value = x, text = x }), "value", "text");
var Provider = new[] {
new { ProviderId = "A", Providername = "A" }
//new DataContracts.RegionKeyValues { RegionId = "B", RegionValue = "B" },
//new DataContracts.RegionKeyValues { RegionId = "D", RegionValue = "D" }
};
ViewData["ProviderName"] = new SelectList(Provider, "ProviderId", "Providername");
**return View("SelectProviderAndContact",providerContactList);**
}
catch (FaultException<MedicareFault> ex)
{
if (ex.Code.Name == typeof(ArgumentException).Name)
{
ViewData["ProviderNotFound"] = true;
ViewData["Error"] = ex.Reason;
return View((object)null);
}
else
{
ViewData["Error"] = Errors.Common.UnknownError;
return View((object)null);
}
}
catch
{
ViewData["Error"] = Errors.Common.UnknownError;
return View((object)null);
}
}
and I have created SelectProviderAndContact.aspx in view.
Please any one help me to open another window with SelectProviderAndContact.aspx
from ajax post call.
Your jquery will have to do almost all the work in opening a window. Using the window.open() method in your javascript you can make your controller send back a specific argument that causes it to open a new window with a certain URL (i.e. TheSmallPopupPageThatViewsResults.aspx?resultId=12345 or something).
Your controller would just decide whether or not to tell the view to open the new window and the view would then open it if it is told to.
With your specific implementation, you may have to create a model or something that stores results in the database so that the controller can save the result and the action and view that are for the popup page can then access that result. Another way of doing it would be to have the arguments that the popup page is called with determine what is viewed on the page. This would eliminate the need for another model, but your urls could get really long really fast if you have a lot of data and I believe that there is generally a limit to how long those urls can be.
I would recommend using JSON or XML to return the data to the javascript so that you can extend the returned object as much as needed. The way I have done it in the past is made several XML tags like <alert>, <refresh>, <redirect>, <somePageSpecificAction>, etc that I have jquery parse using $(theEnclosingTag).each( function () { //...parse here }).
I use mainly MVC3 so I don't know if this is supported in MVC2, but changing ActionResult to JsonResult for the return type and using return this.Json(new { put = "data here" }); for your return statements makes it really easy to use json.
Also, It may be beneficial to use a different action method to process ajax requests. You would then have one action that displays the page, another action to process ajax requests from that page (it could be decorated with [HttpPost] or something), and another method for your popup page view. That would also keep your code short and easier to read. Having long controller methods can get really confusing later down the line when you try to find the location of a specific bug.
EDIT: A specific example: Assuming MVC3 (since that is what I use...I think you can find other ways of doing this...you could use an xml serializer and just output xml) you have your page (Action #1) that displays with all your buttons and stuff (this is where you javascript containing the $("#DeleteButton") and such goes as well). Your javascript makes its AJAX call to another action (SelectContactAJAX or something...this is action #2) with a few arguments which has a return type of JsonResult. Your javascript gets the response back from that ajax-specific action and the response tells it "open a window with the URL /SelectContactForm?choiceId=12345" (or something). The choiceId is a reference that would be used in the background for the SelectContactForm action (yet another separate action...action #3) to know what to display. Your ajax would then call window.open("/SelectContactForm?choiceId=12345") and when the window opens, it calls action #3 which looks up the reference for what it should be displaying and then shows that to the user.
As for getting feedback on what the user entered in the new window and having the original page react, there are various ways in javascript to listen for window closings and such, but I haven't ever had to use this in one of my applications and it is a bit out of the scope of this question.
use colorbox jquery plugin
http://www.jacklmoore.com/colorbox
write code in .aspx page to call .ascx page
parent.$.fn.colorbox({ href: '/IGTR/SaveIGTRPreference/' + id + '?t=' + Math.random(), height: "400", width: "800", overlayClose: false, escKey: false
});
Here SaveIGTRPreference is .ascx page

Resources