ASP.Net FormsAuthentication Rememberme - asp.net

I am using forms authentication in a web application using the built-in Login capabilities, and it has been working well.
I would like to set DisplayRememberMe.visible to false depending on certain conditions (e.g. which Server, ip address, etc). Of course I can manually add visible="false" to the markup shown here, but that seems like a poor way to go.
<asp:CheckBox ID="RememberMe" runat="server" />
<asp:Label ID="RememberMeLabel" runat="server" AssociatedControlID="RememberMe"
CssClass="inline" >Keep me logged in</asp:Label>
Also, I can't figure out which asp field has the DisplayRememberMe field.
But more importantly, in the code behind file, I have added LoginUser.DisplayRememberMe = False, but it is ignored, and the label and checkbox are still visible. I have tried adding it to various events like Page.Load, Page.Init, Login_User.Init, Login_User.Prerender, but the checkbox and label are still visible after the page loads.
Am I using the proper call? Where should I place it to be effective?
This is my first post on SO, so please excuse any poor etiquette.

You can change visibility of CheckBox and Label by creating event of login control as
OnLoad="LoginUser_OnLoad"
On .cs page
protected void LoginUser_OnLoad(object sender, EventArgs eventArgs)
{
var login = (System.Web.UI.WebControls.Login)sender;
var checkbox = login.FindControl("RememberMe");
checkbox.Visible = false;
var label = login.FindControl("RememberMeLabel");
label.Visible = false;
}
You can also put your visibility conditions in LoginUser_OnLoad method.

Related

What is the life cycle of an ASP button?

I'm having an issue with the cycle of a page reload and I can't figure it out. I have an ASP button the runs at the server but it has an associated client side click. The client side Javascript is running correctly and returning true to the button click so it is also running. The Javascript makes a modification to the query string on the URL and this is also working. However, in the C# code behind, the query string is not there. Somewhere, I'm missing something.
The HTML link:
<asp:Button ID="btnRunMOReport" class="button-dbg" runat="server"
Text="Run MO Report" OnClick="btnMO_Report_Click"
OnClientClick="return validateCheckBoxesMO()" />
The JavaScript portion:
function validateCheckBoxesMO() {
token='xyz';
let url1 = window.location.href;
if (url1.indexOf("?") > 0) {
url1 = url1.substring(0, url.indexOf("?"));
}
url1 += "?hiddenToken=" + token;
window.location.replace(url1);
return true;
}
The hiddenToken is now represented on the page (?hiddenToken=xyz).
The code behind:
protected void btnMO_Report_Click(object sender, EventArgs e)
{
MailMessage mailtest = new MailMessage();
mailtest.IsBodyHtml = true;
SmtpClient SmtpServertest = new SmtpClient(ConfigurationManager.AppSettings["smtp_server"]);
mailtest.To.Add("Whoever#test123.com");
mailtest.From = new MailAddress("Whoever#test123.com");
mailtest.Subject = Request.QueryString["hiddenToken"];
mailtest.Body = "Whatever";
}
The mail comes just fine but the subject is blank. Somehow, during the page reload cycle, the query string has not yet been set.
If there is a better way to pass data from the JavaScript to the code behind, I'm all ears.
I want to launch another page from the code behind but I need some data that is returned from the JS. The token is actually something I fetch, process the JSON and now I want to make that token available to the code behind for additional information to add to the new URL I am constructing. Probably TMI for this but it is what I am trying to do.
Thanks for your assistance.
Your script isn't working because the browser makes a POST request to submit the form (and __VIEWSTATE) using the action="" attribute of the <form> that WebForms adds to your page.
When your client-script sets window.location it isn't changing how the <form> will behave. You could use your script to append the new querystring value to the <form>'s action="" attribute and this may work, however it will likely fail if the application has request-validation enabled (in which case ASP.NET will reject a tampered form submission).
As you're using WebForms (and you shouldn't be using WebForms in 2021...) you shouldn't try to fight it unless you understand how it all works (I'm not trying to be condescending: it took me years to figure it all out and I've been using WebForms since 2004).
Instead, provide the value through an <asp:HiddenField>:
Change your .aspx markup to this:
<asp:Button runat="server" ID="btnRunMOReport" class="button-dbg"
Text="Run MO Report" OnClick="btnMO_Report_Click"
OnClientClick="return validateCheckBoxesMO()" />
<asp:HiddenField runat="server" ID="superSecretHiddenField" />
Change your client script to this:
function validateCheckBoxesMO() {
const hiddenFieldId = '<%= this.superSecretHiddenField.ClientID %>';
const hiddenField = document.getElementById( hiddenFieldId );
token='xyz';
hiddenField.value = token;
return true; // <-- This is wrong, btw. Instead use `Event.prototype.stopPropagation()` - but that requires the on-click function to be wired-up correctly and I don't remember the specifics other than that WebForms *doesn't* do things correctly (not out-of-spite, but because WebForms predates the standardisation of client-script events).
}
And your code-behind to this:
protected void btnMO_Report_Click(object sender, EventArgs e)
{
MailMessage mailtest = new MailMessage();
mailtest.IsBodyHtml = true;
SmtpClient SmtpServertest = new SmtpClient(ConfigurationManager.AppSettings["smtp_server"]);
mailtest.To.Add("Whoever#test123.com");
mailtest.From = new MailAddress("Whoever#test123.com");
mailtest.Subject = this.superSecretHiddenField.Value;
mailtest.Body = "Whatever";
}
As noted, a button post back will in general over-write the url that you change. Unless you actually do a navigation client side that is caused by the js, then it will not persist.
So, on the most simple level, just drop in a text box, or hidden field, and put the value you need/want into that hidden textbox or field.
So, client side? Markup?
You can use this:
<asp:Button ID="Button1" runat="server" Text="Delete"
OnClientClick="SetHidden();"/>
<asp:HiddenField ID="HiddenField1" runat="server" ClientIDMode="Static"/>
<br />
<script>
function SetHidden() {
hField = document.getElementById('HiddenField1');
hField.value = 'zoo';
return true;
}
</script>
So in above, we set our value in js to zoo, and of course we do return true. If we return false then the asp.net button code server side will not run - so we can control this, or even say pop up a confirm dialog and return true/false based on that to control if the server side code behind will run.
Server side, code behind? You can now use this:
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Debug.Print(HiddenField1.Value)
End Sub
So the above is easy, clean. You can also use a text box, and set the style="display:none", but a hidden field is just as well and easy.

Juice UI - Textbox inside accordion issue

I'm unable to retrieve the content of a textbox that's inside an accordion panel. My markup is as follows:
<juice:Accordion ID="Accordion1" runat="server">
<juice:AccordionPanel ID="AccordionPanel1" runat="server" Title="Media ID">
<PanelContent>
<asp:Label ID="LabelMediaID" runat="server" Text="Media ID" AssociatedControlID="TextBoxMediaID"></asp:Label>
<asp:TextBox ID="TextBoxMediaID" runat="server"></asp:TextBox>
</PanelContent>
</juice:AccordionPanel>
My server side code is triggered when the user clicks a button:
protected void ButtonSearch_Click(object sender, EventArgs e)
{
// Retrieve controls within accordion panels
TextBox TextBoxMediaID = (TextBox)AccordionPanel1.FindControl("TextBoxMediaID");
string mediaID= "abc";
if (TextBoxMediaID != null)
mediaID= TextBoxMediaID.Text;
I'm able to successfully retrieve my textbox control but when I try to access its Text property it's always empty.
Can someone help me? I'm afraid I'm reasonably new to the world of ASP.NET, Juice etc. Thanks.
It turned out that my problem was caused by having an ASP.NET project that used master pages.
If you're not using master pages then
TextBox TextBox1 = (TextBox)AccordionPanel1.FindControl("TextBox1");
string content= Request.Form[TextBox1.UniqueId];
works perfectly. However, when using a master page with a ContentPlaceHolder then use the following code:
ContentPlaceHolder cph = (ContentPlaceHolder)Master.FindControl("MainContent");
TextBox TextBox1 = (TextBox)AccordionPanel1.FindControl("TextBox1");
string content= Request.Form[cph.UniqueID + "$" + TextBox1.UniqueId];
Hopefully this will save someone a lot of time!
Option 1 - Quick fix
For your page, make ClientIDMode="static" in page directive and then use Request.Form["TextBoxMediaID"] to get value of your text box.
Option 2 - Debug
Go to debug mode and try AccordionPanel1.Controls[0].("TextBoxMediaID"); or AccordionPanel1.Controls[0].Controls[0].("TextBoxMediaID"); because you don't know how many server side controls are there. Simple solution would be to use find control recursive function.

Make Control Visible/InVisible in ASP

I have this hyperlink called “SEND” in a ASP page called Home and here it is:
<asp:TemplateField>
<ItemTemplate>
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl='<%# Eval("Post_ID", "~/RCA.aspx?Post_ID={0}") %>'
Text="SEND"></asp:HyperLink>
</ItemTemplate>
when the user clicks the hyperlink it goes to another page called RCA and in this page there is a Button and here it is the code:
<asp:Button ID="btnRCA" runat="server" onclick="Button1_Click"
Text="Assign RCA" Width="147px" />
so I want this button to be visible only when clicked the hyperlink in the HOME page. I am planning to have another button or control in the RCA page that will make it invisible when clicked or before someone leaves the page they have to make it invisible the Button by clicking some other control. can someone help me with this? thanks
Use a QueryString parameter.
Home.aspx
//When linked to RCA.aspx from Home.aspx, a parameter called ShowButton=1 is included
//in the URL.
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl='<%# Eval("Post_ID", "~/RCA.aspx?Post_ID={0}&ShowButton=1") %>'
Text="SEND"></asp:HyperLink>
RCA.aspx
//By default, since you want the button to NOT appear for all incoming traffic EXCEPT
//that which came from Home.aspx, the button's Visible property is set to false.
<asp:Button ID="btnRCA" runat="server" onclick="Button1_Click"
Text="Assign RCA" Width="147px" Visible="false" />
RCA.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
//If the querystring has a parameter called ShowButton and it's equal to "1",
//then set the button to Visible = true.
//Else, do nothing, keeping the button in it's default, Visible=false state.
//By putting this in an "IsPostback == false" check, you can guarantee that this will
//only happen on first page_load, and won't be triggered again even if you do other
//actions in the page that cause Postback
//For example, if you don't use this !IsPostback check, and you end up creating some
//new function that causes the button to be hidden again, but then you make a
//selection from a dropdown list that causes postback, you will trigger the call to
//make the button Visible again, even though that's probably what you don't want at
//this point, since your other new function set it to Visible = false.
if (!IsPostback)
{
if (Request.QueryString["ShowButton"] == "1")
{
RCAbtn.Visible = true;
}
if (Request.QueryString["Post_ID"] != null)
{
//do whatever you need to with the post ID
}
}
}
SomeOtherPage.aspx.cs
Response.Redirect("RCA.aspx?Post_ID=1234"); //button will be invisible
And then let's say later that you want to re-direct from some other page and have the button be visible, like the redirect from Home:
Response.Redirect("RCA.aspx?Post_ID=1234&ShowButton=1"); //button will be visible
If you don't like cluttering up your URL or you feel that it looks tacky to have what you are doing so plainly available to the user's eyes, you don't necessarily need to use "ShowButton". You could say ?Post_ID=1234&fkai3jfkjhsadf=1, and then check your query string for "fkai3jfkjhsadf". I like to do that sometimes because then from the users point of view, it makes me look like I'm doing something really technical and encrypted, and not just passing around a bunch of basic instructions in plain English :) Downside there is you need keep track of your own query string parameters.
Edit:
If you want to get the URL with only the Post_ID and nothing else, you can do this:
string currenturl = Request.Url.ToString(); //get the current URL
string urlToSend = currenturl.Substring(0, currenturl.IndexOf("?")); //cut off the QueryString entirely
urlToSend += "?Post_ID=" + Request.QueryString["Post_ID"]; //re-append the Post_ID
Be aware that your call to Substring will cause an exception if the URL doesn't have a QueryString, so please patch that up in whatever way works best for you (try/catch, etc.).
After that, you should just be able to use the "urlToSend" string in your mailMessage.Body.
on your second page in your page_load, try this:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["Post_ID"] != null)
{
btnRca.Visible = true;
}
}
I don't know how you want to handle the visibility of this button in other cases, but this should answer your particular question.

UpdatePanel resetting object to inital state

I have an application that I am currently writing that works by iterating through nodes, and then updating the page with the information of the current node. I have an UpdatePanel in the page which contains a label, textbox, and a button. The label lists the currently available children of the current node, the user enters in which child they want to go to into the textbox, and then hits the submit button. I set the new value of the node in the submit button's event handler.
Here's my problem: Every time I enter in which node I want to navigate to, the object resets its value to the value it was initially initialized to. I have even put this same code into a Windows Form to validate that it's working correctly to iterate through my tree, and it works as it should, so I know my problem is AJAX-related.
This is the first app that I have written using AJAX, so I am still in the process of learning how it works. Any help would be greatly appreciated. I have Googled and searched SO through and through.
Here is the HTML:
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager" runat="server"></asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="question" runat="server" Text=""></asp:Label>
<br />
<asp:TextBox ID="answer" runat="server"></asp:TextBox>
<br />
<asp:Button ID="Submit" runat="server" Text="Submit" onclick="Submit_Click" />
</ContentTemplate>
</asp:UpdatePanel>
</form>
And the C#:
protected void Submit_Click(object sender, EventArgs e)
{
int ans = int.Parse(answer.Text);
if (!current.ChildIDs.Contains(ans))
{
return;
}
current = tree.Node(ans);
question.Text = current.Question;
}
current is the current node, which has a public ArrayList of all of its children's IDs. tree is the NodeTree I have; calling Node just returns the new node. Both current and Tree get initialized in the Page_Load event, and that only fires once (when the page is first loaded).
It's really pretty simply code; I'm just having difficulty understanding why the AJAX isn't working correctly.
I have even put this same code into a
Windows Form to validate that it's
working correctly to iterate through
my tree, and it works as it should, so
I know my problem is AJAX-related.
It sounds like you're expecting ASP.NET to remember what the object current is between requests, since that's how Windows forms applications work.
Web applications are stateless - after each request, ASP.NET discards all your variables. To access the variable during a subsequent request, you have to either:
1) Send enough data with the request to reconstruct the variable. You can do this using a querystring parameter or an HTML form value (the hidden fields another response mentioned).
2) Save the variables in a Session store (which can be in-memory or backed by a database).
3) Store the value in a coookie.
Of these three, it's easiest to show you how to use Session, given what you've shared in your question. However, beware: session has its risks - by default, ASP.NET session objects are stored in-memory, and it's a potential security hazard. But here's how you should be able to get your application to work.
// In your Page_Load code that initializes your 'current' variable
// When the user first requests the page, create a new Node
if (! this.IsPostBack)
{
Node current = new Node(); //
Session("currentNode") = current;
}
// When the user clicks a button on the page (posts), use the
// node in session instead
else
{
current = Session("currentNode");
}
When you update non-form elements in the browser (labels, literals, etc.), .NET is unable to see any of the changes you've made.
Try adding a hidden input for each label that records the new value. Then within the method you have wired up to the button's OnClick event, do something like this:
myLabel.Text = myHiddenInput.value;
I think you just need to tell the updatepanel to update itself. Try this:
protected void Submit_Click(object sender, EventArgs e)
{
int ans = int.Parse(answer.Text);
if (!current.ChildIDs.Contains(ans))
{
return;
}
current = tree.Node(ans);
question.Text = current.Question;
UpdatePanel.Update();
}

ASP.Net - repeating input boxes on the client side using Repeater

I have the following requirement for creating a user profile in my application:
User should be able to enter multiple phone numbers/email addresses in his profile.
The screen looks somewhat like this:
- By default, on page load a single textbox for phone and email are shown.
- User can click a "+" button to add additional numbers/addresses.
- On clicking the "+" button we need to add another textbox just below the first one. User can add as many numbers/addresses as he wants. On submit, the server should collect all numbers/emails and save it in DB.
I tried using the Repeater control to do this. On page_load I bind the repeater to a "new arraylist" object of size 1. So, this renders fine - user sees a single textbox with no value in it.
When he clicks the "+" button, I ideally want to use javascript to create more textboxes with similar mark-up as the first.
My questions are these:
Can I render the new textboxes anyway using js? I notice that the HTML rendered by the repeater control is somewhat complex (names/ids) etc. and it might not be possible to correctly create those controls on client-side.
If there is a way to do #1, will the server understand that these additional inputs are items in the repeater control? Say, I want to get all the phone numbers that the user entered by iterating over Repeater.DataItems.
Conceptually, is my approach correct or is it wrong to use the Repeater for this? Would you suggest any other approach that might handle this requirement?
Coming from a Struts/JSP background, I am still struggling to get a grip on the .NET way of doing things - so any help would be appreciated.
The repeater control may be a bit of overkill for what you're trying to accomplish. It is mainly meant as a databound control for presenting rows of data.
What you can do is to dynamically create the boxes as part of the Page_Load event (C#):
TestInput.aspx :
<form id="form1" runat="server">
<asp:HiddenField ID="hdnAddInput" runat="server" />
<asp:Button ID="btnPlus" OnClientClick="setAdd()" Text="Plus" runat="server" />
<asp:PlaceHolder ID="phInputs" runat="server" />
</form>
<script type="text/javascript">
function setAdd() {
var add = document.getElementById('<%=hdnAddInput.ClientID%>');
add.value = '1';
return true;
}
</script>
TestInput.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["inputs"] == null)
ViewState["inputs"] = 1;
if (hdnAddInput.Value == "1")
{
ViewState["inputs"] = int.Parse(ViewState["inputs"].ToString()) + 1;
hdnAddInput.Value = "";
}
for (int loop = 0; loop < int.Parse(ViewState["inputs"].ToString()); loop++)
phInputs.Controls.Add(new TextBox() { ID = "phone" + loop });
}
I ended up using a PlaceHolder to dynamically add the text boxes and a HiddenField to flag when another TextBox needed to be added. Since the IDs were matching, it maintains the ViewState of the controls during each postback.
Welcome to the hairball that is dynamically-added controls in ASP.NET. It's not pretty but it can be done.
You cannot add new fields dynamically using javascript because the new field would have no representation in the server-side controls collection of the page.
Given that the requirements are that there is no limit to the number of addresses a user can add to the page, your only option is to do "traditional" dynamic ASP.NET controls. This means that you must handle the adding of the control server-side by new-ing a new object to represent the control:
private ArrayList _dynamicControls = new ArrayList();
public void Page_Init()
{
foreach (string c in _dynamicControls)
{
TextBox txtDynamicBox = new TextBox();
txtDynamicBox.ID = c;
Controls.Add(txtDynamicBox);
}
}
public void AddNewTextBox()
{
TextBox txtNewBox = new TextBox();
txtNewBox.ID = [uniqueID] // Give the textbox a unique name
Controls.Add(txtNewBox);
_dynamicControls.Add([uniqueID]);
}
You can see here that the object that backs each dynamically-added field has to be added back to the Controls collection of the Page on each postback. If you don't do this, data POSTed back from the field has nowhere to go.
If you want to user the repeater, I think the easiest way is to put the repeater in a ASP.Net AJAX update panel, add the extra textbox on the sever side.
There are definitely other way to implement this without using repeater, and it maybe much easier to add the textbox using js.
No, but you can create input elements similar to what TextBox controls would render.
No. ASP.NET protects itself from phony data posted to the server. You can't make the server code think that it created a TextBox earlier by just adding data that it would return.
The approach is wrong. You are trying to go a middle way that doesn't work. You have to go all the way in either direction. Either you make a postback and add the TextBox on the server side, or you do it completely on the client side and use the Request.Form collection to receive the data on the server side.

Resources