Viewstate expires after some time for application page in SharePoint 2013? - asp.net

I have a simple ASP application page added in a SharePoint project just for presentation purposes, so it's ASP web forms page is hosted in SharePoint.
HTML:
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
<asp:Label runat="server">Number 1:</asp:Label>
<asp:TextBox ID="num1" runat="server"></asp:TextBox>
<asp:Label runat="server">Number 2:</asp:Label>
<asp:TextBox ID="num2" runat="server"></asp:TextBox>
<asp:Label runat="server">Result:</asp:Label>
<asp:TextBox ID="res" runat="server"></asp:TextBox>
<asp:Button Text="ADD Numbers" runat="server" OnClick="Unnamed_Click" />
<asp:ListBox runat="server" ID="list" />
<asp:Label runat="server" ID="previousListValue"></asp:Label>
<asp:Label runat="server">Exception:</asp:Label>
<asp:TextBox ID="exception" runat="server"></asp:TextBox>
</asp:Content>
Here is code behind:
public partial class Default : LayoutsPageBase
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
list.DataSource = new List<ListItem>() {
new ListItem("value1", "1"),
new ListItem("value2", "2"),
new ListItem("value3", "3"),
};
list.DataBind();
}
}
protected void Unnamed_Click(object sender, EventArgs e)
{
try
{
res.Text = Convert.ToString(int.Parse(num1.Text) + int.Parse(num2.Text));
previousListValue.Text = "Previous list selected value is: " + list.SelectedItem.Value;
exception.Text = string.Empty;
}
catch (Exception ex)
{
exception.Text = ex.GetType().ToString() + "\t" + ex.Message;
}
}
}
When you click "ADD Numbers" button and addition of num1 and num2 textboxes is appended to the res textbox and selected value of ListBox is shown in label next to it. This works flawlessly if correct values are entered for a number and an item is selected in ListBox.
If the page is left (not interacted with) for about 10-15 minutes and "ADD Numbers" button is clicked, NullReferenceException will be thrown for list.SelectedItem.Value and also textBoxes will be empty. What happened is that the application is in postBack state(Page.IsPostBack is true) but viewstate is not restored.
I guess this has something to do with ViewState being moved to distributed cache as of version 2013 but can someone clarify this for me, and suggest me the most effective way to go about this, without changing AppFabric configuration, because 10-15 minutes of ViewState perversion is not acceptable.

As the ViewState is saved in the user's session, it is possible for
ViewState to expire if a page is not posted back within the session
expiration time.
You can configure your session timeout in web.config file (Session timeout in ASP.NET):
<sessionState timeout="60" />
(Where 50 and 60 are minutes)
You can also check if your session expired using this sample code in Master Page's Page_Load method:
if (Session.Contents.Count == 0)
{
//Session dead!
}
else
{
//Session alive!
}
Or save the logged user and test if it's null:
if (Session["userId"] == null)
{
//Session dead!
}
else
{
//Session alive!
}

Related

How do I load two ASP.NET UserControls on Demand?

I want load two user controls on demand.
asp:UpdatePanel ID="UpdatePanel1" runat="server"
ContentTemplate
asp:Button ID="Button1" runat="server" Text="Button" UseSubmitBehavior="false"
OnClick="Button1_Click" /
div id='Div_UserControlPlace' enableviewstate="true" runat="server"
/div
/ContentTemplate
Triggers
asp:PostBackTrigger ControlID="Button1" /
/Triggers
/asp:UpdatePanel
asp:UpdatePanel ID="UpdatePanel2" runat="server"
ContentTemplate
asp:Button ID="Button2" runat="server" Text="Button" UseSubmitBehavior="false"
OnClick="Button2_Click" /
div id='Div_UserControlPlace2' enableviewstate="true" runat="server"
/div
/ContentTemplate
aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
Control FeaturedProductUserControl = new Control();
FeaturedProductUserControl = LoadControl("WebUserControl1.ascx");
FeaturedProductUserControl.EnableViewState = true;
Div_UserControlPlace.Controls.Add(FeaturedProductUserControl);
}
protected void Button2_Click(object sender, EventArgs e)
{
Control FeaturedProductUserControl2 = new Control();
FeaturedProductUserControl2 = LoadControl("WebUserControl2.ascx");
FeaturedProductUserControl2.EnableViewState = true;
Div_UserControlPlace2.Controls.Add(FeaturedProductUserControl2);
}
I load the first user control by clicking on the first button - this works properly but when I click on the other button to load the second UserControl, the first UserControl disappears and the second UserControl loads.
Thanks
IFA_User
You should use the Placeholder control to dynamically add your controls to the form.
Take a look at my last responses about dynamic controls:
OnClick event of dynamically created LinkButtons is not working
Dynamically Added DropDownlists Are Not Firing SelectedIndexChanged Event
Dynamically create an ImageButton
Now I already have some code working for demo purpose, each dynamic user controls keeps its state across post backs
This is the output:
ASPX
<asp:PlaceHolder runat="server" ID="addresses" /><br />
<asp:Button Text="Add Address" runat="server" ID="addAddress" OnClick="addAddress_Click" />
ASPX Code behind
protected void Page_PreLoad(object sender, EventArgs e)
{
for (int i = 0; i < this.DynamicControlsCount; i++)
{
var c = this.LoadControl("~/AddressControl.ascx");
this.addresses.Controls.Add(c);
}
}
protected void addAddress_Click(object sender, EventArgs e)
{
this.DynamicControlsCount++;
var c = this.LoadControl("~/AddressControl.ascx");
this.addresses.Controls.Add(c);
}
protected int DynamicControlsCount
{
get
{
if (this.ViewState["ac"] == null)
{
return 0;
}
return (int)this.ViewState["ac"];
}
set
{
this.ViewState["ac"] = value;
}
}
ASCX
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="AddressControl.ascx.cs" Inherits="WebApplication1.AddressControl" %>
<asp:Panel ID="Panel1" runat="server" GroupingText="Address" DefaultButton="btnSave">
Street: <asp:TextBox runat="server" ID="txtStreet" /><br />
City: <asp:TextBox runat="server" ID="txtCity" /><br />
<asp:Button Text="Save" runat="server" ID="btnSave" OnClick="btnSave_Click" />
</asp:Panel>
<asp:Panel runat="server" GroupingText="Address Summary" Visible="false" ID="summary">
<asp:Label ID="lblStreet" runat="server" /><br />
<asp:Label ID="lblCity" runat="server" />
</asp:Panel>
ASCX Code behind
protected void btnSave_Click(object sender, EventArgs e)
{
this.summary.Visible = true;
this.lblCity.Text = "Selected city: " + this.txtCity.Text;
this.lblStreet.Text = "Selected street: " + this.txtStreet.Text;
}
When a user control is created in the HTML, asp.net will persist across postbacks without any user interaction. But if you are loading them programatically (dynamically), they will not persist accross postbacks. So if you load them programmatically, you have the added task of persisting them programmatically as well. Use the ViewState (or Session I suppose) to store what has been loaded and perhaps any other necessary information that needs to be loaded between postbacks. Every single postback will require you to reload every control or else they will disappear.
There are couple of ways of doing it:
U can load the UserControls using Ajax. Benefit of using Ajax, is ur page does not get post back, thus for example, on click event of Button1, call a ajax(traditional/Jquery) to load UserControl1, and on button click of Button2 User control2.
Put the two button in two different updated panel, by doing this the click event will only refresh a part of ur page.
U have to save somewhere (ViewState/Session),which buttons are clicked, and upon clicking of any button check the value of that variable, and explicit load the control.
Points to note - If u want to get ur data back when ur page made a complete postback, then u have to add the controls keeping in mind the Page load event cycle.

Pass username & password to an invisible Login Control to validate?

In my master page, on the menu there is an icon which uses Jquery to slide, showing 2 textboxes (username, password) for users to enter & 1 submit button. My idea is that after submitting, I get values of these 2 fields to assigned it to an invisible Login Control in my MasterPage, then validate automatically.
I could get values and assign but problem is I don't know how to trigger the Login button in Login Control (how to force it to process information)? the DataBind() func doesn't work
Master.master
<div id="login">
<p>
<asp:Login ID="Login2" runat="server" DestinationPageUrl="~/Index.aspx" LoginButtonStyle-CssClass="button_login"
TextBoxStyle-CssClass="input-name" Visible="false">
</asp:Login>
<asp:TextBox ID="inputUser" CssClass="input-name" Text="Username" runat="server"></asp:TextBox>
<asp:TextBox ID="inputPassword" CssClass="input-pass" Text="Password" runat="server"
TextMode="Password"></asp:TextBox>
<asp:Button ID="btn_login" CssClass="button_login" runat="server" OnClick="triggerLogin" />
</p>
</div>
Main.master.cs:
protected void triggerLogin(object sender, EventArgs e)
{
Login2.UserNameLabelText = inputUser.Text;
Login2.PasswordLabelText = inputPassword.Text;
Login2.DataBind();
}
Actually I already have a login page which processes individually, is it possible to pass information to that page to process?
You can add your username and password int o a session.
Something like:
Session["user"] = inputUser.Text;
Session["pass"] = inputPassword.Text;
By using that you can access the username,password in your pages.
var myusername = Session["user"].ToString();
var mypassword= Session["pass"].ToString();
Check this on MSDN:
ASP.NET State Management Overview
How to: Pass Values Between ASP.NET Web Pages
Regards
Yeah, I've found out the solution, without having to use Login Control. I can do it manually.
<asp:TextBox ID="inputUser" CssClass="input-name" Text="Username" runat="server"></asp:TextBox>
<asp:TextBox ID="inputPassword" CssClass="input-pass" Text="Password" runat="server"
TextMode="Password"></asp:TextBox>
<asp:Button ID="btn_login" CssClass="button_login" runat="server" OnClick="triggerLogin" />
Codebehind:
protected void triggerLogin(object sender, EventArgs e)
{
TextBox txtbxInputUser = (TextBox)Page.Master.FindControl("inputUser");
TextBox txtbxInputPass = (TextBox)Page.Master.FindControl("inputPassword");
Label samplelabel1 = (Label)Page.Master.FindControl("sampleLabel1");
if (System.Web.Security.Membership.ValidateUser(txtbxInputUser.Text, txtbxInputPass.Text))
{
System.Web.Security.FormsAuthentication.SetAuthCookie(txtbxInputUser.Text, false);
}
else
{
Response.Redirect("Login.aspx?Attempt=wrong");
}
}

How do I maintain user entered text in a TextBox nested in an UpdatePanel between updates?

I have an ASP.Net UpdatePanel that updates on a timer. Within the UpdatePanel and nested in a GridView, I have a TextBox that the user enters a value in with a submit button. Everything works fine, except if the user does not submit the value before the timed interval, the text is removed from the TextBox.
Is there a way to persist the user entry into the TextBox between updates? Is there a better way of doing this?
All suggestions welcome.
Respectfully,
Ray K. Ragan
Code Postscript:
aspx:
<script type="text/javascript">
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_beginRequest(beginRequest);
function beginRequest() {
prm._scrollPosition = null;
}
</script>
<asp:Timer ID="Timer1" runat="server" Interval="900" OnTick="Timer1_Tick"></asp:Timer>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Timer1" EventName="Tick" />
</Triggers>
<ContentTemplate>
<asp:DataList RepeatColumns="5" RepeatDirection="Horizontal" ID="dlMine" runat="server" OnItemCommand="Item_Command">
<ItemTemplate>
<div style="border:1px solid black;margin:3px;height:300px;text-align:center;padding:5px;">
<div style="width:150px;">
<asp:Label ID="lblTitle" runat="server" Text='<%# left(DataBinder.Eval(Container.DataItem,"title").ToString(), 75) %>'></asp:Label>
</div>
<asp:Label ID="Label1" runat="server" Text='<%# (DateTime)DataBinder.Eval(Container.DataItem,"end_date") %>'></asp:Label>
<br />
<asp:Label ID="Label2" runat="server" Text='<%# String.Format("{0:C}",DataBinder.Eval(Container.DataItem,"current_value")) %>'></asp:Label>
<br />
<asp:TextBox ID="txtNewValue" runat="server"></asp:TextBox>
<asp:Button Visible='<%# (isInThePast((DateTime)DataBinder.Eval(Container.DataItem,"end_date"))) ? false : true %>' CssClass="bid_button" runat="server" CommandArgument='<%# Eval("ID") %>' CommandName="Revalue" ID="btnBid" Text="Submit New Valuation" />
</div>
</ItemTemplate>
</asp:DataList>
</ContentTemplate>
</asp:UpdatePanel>
Codebehind:
protected void Page_Load(object sender, EventArgs e)
{
Timer1.Tick += new EventHandler<EventArgs>(Timer1_Tick);
if (!IsPostBack)
{
dataBindList();
}
}
protected void dataBindList()
{
if (Request.QueryString["GroupID"] != null)//Are they coming here with a URL var? If so, build content object
{
List<Item> itemList = ItemManager.getItemsByGroupID(Request.QueryString["GroupID"].ToString());
dlMine.DataSource = itemList.Take(15);
dlMine.DataBind();
}
}
protected void Timer1_Tick(object sender, EventArgs e)
{
dataBindList();
UpdatePanel1.Update();
}
protected void Item_Command(Object sender, DataListCommandEventArgs e)
{
if (e.CommandName == "Revalue")
{
Person p = (Person)Session["Person"];
foreach (DataListItem item in dlMine.Items)
{
string textBoxText = ((TextBox)item.FindControl("txtNewValue")).Text;
Utilities.writeLog("txtNewValue: " + textBoxText, 1);
}
dataBindList();
UpdatePanel1.Update();
}
}
You're rebinding the DataList every time the Timer ticks. All changes in the ItemTemplates of the DataList will be lost on postback.
Why not use Javascript to "pause" the timer whenver one of the textboxes gains focus. This will prevent the Timer from firing and let users finish entering text. Once they leave the textbox of "onblur" then you can restart the timer.
Update
The following will take a bit of effort to make it happen but you can do something like:
When the Timer posts back, before rebinding, iterate over the DataList while searching for textboxes with text in them. Something like:
foreach (DataListItem item in dlMine.Items)
{
//find the textbox control and check for text
}
At this point, you'll know which rows need there textboxes repopulated. Store this information in a hashtable.
In the DataList ItemDataBound event, check each rowID against the hashtable to see if its corresponding textbox exists. If so, repopulate the textbox in the DataList row.
Are you initializing the TextBbox value in your code-behind, perhaps in Page_Load or another page method?
TextBox1.Text = "";
If so, that code is executing on every timer event. You can prevent that like this:
if (! IsPostback) {
TextBox1.Text = "";
}
The first request that hits an ASP.NET page is usually an HTTP GET request, while ASP.NET buttons and update panel events issue HTTP POST requests. So the code above will clear TextBox1 the first time you access the page, but leave the value alone when receiving requests from itself. (If you really are setting the text box's value to its default - empty - you could just remove the initialization code.)

ASP.NET randomly caching output

I created a basic asp.net page, with a GridView and simple controls for search and paging purposes. If I click on the "next page" button, sometimes the output is exactly the same than the previous postback, sometimes is the correct output.
This behavior was found using regular and ajax postbacks. And I have used Fiddler and confirmed that is not the browser caching the output.
And I am not using any outputcache directive.
Example:
open page, click "next", it's still page 1. click "next" again, now it's page 3.
It is completely random, sometimes it works fine, sometimes don't. Does anyone know what could be causing this behavior?
ASPX Page:
<asp:Panel ID="PanelSearch" runat="server" GroupingText="Search Result" HorizontalAlign="Left"
Width="100%" Style="clear: both">
<uc1:dashboard_search ID="Dashboard_search1" runat="server" OnOnNeedSubs="Dashboard_search1_OnNeedSubs" /><br />
<asp:Button ID="btnBack" runat="server" Text="Previous page" Visible="false"
onclick="btnBack_Click" />
<asp:Label ID="lblPageNumber" runat="server"></asp:Label>
<asp:Button ID="btnNext"
runat="server" Text="Next Page" Visible="false"
onclick="btnNext_Click"/>
<asp:HiddenField ID="hidPageNumber" runat="server" Value="0" />
</asp:Panel>
This code is inside an UpdatePanel (but without an UpdatePanel it still occurs the same thing).
This is the code behind code:
public void Dashboard_search1_OnNeedSubs(object sender, SubSSDEventArgs e)
{
e.SubSSDs = doSearch();
}
protected List<SubSSD> doSearch()
{
// [filter code]
int total = SubSSD.getTotalNumber();
int page = Convert.ToInt32(hidPageNumber.Value);
if (page == 0)
btnBack.Visible = false;
else
btnBack.Visible = true;
if (page + 26 >= total)
btnNext.Visible = false;
else
btnNext.Visible = true;
lblPageNumber.Text = "Page " + Convert.ToInt32((page / 25) + 1) + "/" + Convert.ToInt32((total / 25) + 1);
List<SubSSD> subssds = SubSSD.search(page, page + 26);
return subssds;
}
protected void btnBack_Click(object sender, EventArgs e)
{
int page = Convert.ToInt32(hidPageNumber.Value);
hidPageNumber.Value = Convert.ToString(page - 25);
}
protected void btnNext_Click(object sender, EventArgs e)
{
int page = Convert.ToInt32(hidPageNumber.Value);
hidPageNumber.Value = Convert.ToString(page + 25);
}
To completely eliminate the browser side, I would attach a random url parameter. I'll note that most of the major javascript libraries do this transparently with their ajax features.
Sounds to me like you should either put some logging in place or a lot of breakpoints to identify exactly which methods are being called in which order.
I suspect that the grid binding is happening out of order of your next page code.
Guys, i found out why it was having such strange behavior, there was a OutputCache directive in the user control, for caching the content for 5 seconds.

ListView + ObjectDataSource SelectMethod called twice when EnableViewState="false"

Note: This question has been completely modified now that I have a simpler example.
I have set up a sample page which only has a ListView and ObjectDataSource. The first time the page comes up (!IsPostBack), my GetList method is called once. After paging (IsPostBack), the GetList method is called twice--the first time with the old paging values and the second time with the new values.
If I set EnableViewState="true" on the ListView, then the GetList method is only called once. It seems to me that the ListView wants an "initial state", which it either gets from ViewState or by re-running the method.
Is there any way to disable ViewState on the ListView and also prevent SelectMethod from being called twice?
ASPX page:
<asp:ListView ID="TestListView" runat="server" DataSourceID="ODS" EnableViewState="false">
<LayoutTemplate>
<asp:PlaceHolder ID="itemPlaceHolder" runat="server" />
<asp:DataPager ID="TestPager" runat="server" PageSize="10">
<Fields>
<asp:NumericPagerField />
</Fields>
</asp:DataPager>
</LayoutTemplate>
<ItemTemplate>
<div><%# Eval("Title") %></div>
</ItemTemplate>
</asp:ListView>
<asp:ObjectDataSource ID="ODS" runat="server" SelectMethod="GetList" SelectCountMethod="GetListCount"
TypeName="Website.Test" EnablePaging="true" />
ASPX code-behind:
namespace Website
{
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
public IList<DataItem> GetList(int maximumRows, int startRowIndex)
{
return GetListEnumerable().Skip(startRowIndex).Take(maximumRows).ToList();
}
public IEnumerable<DataItem> GetListEnumerable()
{
for (int i = 0; i < 100; i++)
{
yield return new DataItem { Title = i.ToString() };
}
}
public int GetListCount()
{
return 100;
}
}
public class DataItem
{
public string Title { get; set; }
}
}
Either turn ODS caching on.
<asp:ObjectDataSource ID="ODS" ... EnableCaching="true" />
This way the GetList will be called only when new data is needed. Post backs to pages that already had data retrieved will use the cached version and not call the GetList.
Or move your DataPager out of the ListView and set the PagedControlID property.
Actually you should be using the OnSelecting event.
What happens is that ObjectDataSource calls the method SelectMethod twice
First time it gets the data.
Next time it gets the count.
So I think you have to implement the OnSelecting event
<asp:ObjectDataSource ID="ODS" runat="server" SelectMethod="GetList" SelectCountMethod="GetListCount"
OnSelecting="ods_Selecting">
TypeName="Website.Test" EnablePaging="true" />
and then cancel the event when the ObjectDataSource tries to call the count method.
protected void ods_Selecting(object sender,
ObjectDataSourceSelectingEventArgs e)
{
if (e.ExecutingSelectCount)
{
//Cancel the event
return;
}
}
You can look for full implementation as mentioned in the link below
http://www.unboxedsolutions.com/sean/archive/2005/12/28/818.aspx
Hope this helps.
I had a similar problem where it worked different depending on browser. IE one way and all other browsers one way.. Might not be the same issue as you have.
I solved it this way:
protected void DropDownDataBound(object sender, EventArgs e)
{
// Issue with IE - Disable ViewState for IE browsers otherwhise the dropdown will render empty.
DropDownList DDL = (DropDownList)sender;
if (Request.Browser.Browser.Equals("IE", StringComparison.CurrentCultureIgnoreCase))
DDL.ViewStateMode = System.Web.UI.ViewStateMode.Disabled;
else
DDL.ViewStateMode = System.Web.UI.ViewStateMode.Inherit;
}

Resources