How can I use my own random captcha in ASP.NET? - asp.net

For hands on experience, I am generating random numbers and compare their sums on submission, but every time, I press button, random numbers are changing, How can I stop happening this? I considered different experiments, but not able to do that.
Here is my class code for random numbers:
public class Captcha
{
int num1, num2, total;
public int N1
{
get
{
return num1;
}
}
public int N2
{
get
{
return num2;
}
}
public int Total
{
get
{
return total;
}
}
Random r = new Random();
public Captcha()
{
Random r = new Random();
num1 = r.Next(1, 11) * 10;
num2 = r.Next(1, 11);
total = num1 + num2;
}
}
Now, I am using this one on Page_Load event like this :
Captcha c = new Captcha();
protected void Page_Load(object sender, EventArgs e)
{
Label2.Text = c.N1.ToString();
Label3.Text = c.N2.ToString();
}
How can I accomplished this one?
Thanks.

Since you are creating object of Captcha outside the Page Load event, it will get re-created whenever a call to the page happens.
You might be aware that internet is state-less so whenever there is a call to the Page, a new page gets generated, and hence new Captcha object. So you need to maintain the Captcha object in some state management like view state.
Your code should be something like this.
Captcha c;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
c = new Captcha();
Label2.Text = c.N1.ToString();
Label3.Text = c.N2.ToString();
ViewState["c"] = c;
}
}
Then on button click you need to type cast the viewstate back to "c". Something like this.
//button click
c = (Captcha)ViewState["c"];
if(TextBox1.Text.Equals......)
Maybe you need to mark your Captcha class as serializable as it might throw error.
I hope this will help.
Regards,
Samar

Related

Null after onClick action

I'm starting with asp.net, but i'm not quite sure what am I doing wrong. Actually my first step in asp is to make a calculator but after 2h of looking for answer i've decided to ask you about that.
I have 10 buttons with [0,1,2...9], 4 action buttons [+,-,*,/] and one button to calculate [=]:
int firstNumber, secondNumber;
Button lastClicked;
bool isFirstNumberSet;
protected void Page_Load(object sender, EventArgs e)
{
firstNumber = 0;
isFirstNumberSet = false;
lastClicked = new Button();
}
public void addToTextbox(object sender, EventArgs e)
{
Button number = (Button)sender;
TextBox1.Text += number.Text;
}
public void doSomething(object sender, EventArgs e)
{
if (isFirstNumberSet.Equals(false)) firstNumber = int.Parse(TextBox1.Text);
else secondNumber = int.Parse(TextBox1.Text);
lastClicked = new Button();
lastClicked = (Button)sender;
isFirstNumberSet = true;
TextBox1.Text = "";
}
public void calculate(object sender, EventArgs e)
{
switch (lastClicked.ID)
{
case "ButtonPlus":
TextBox1.Text = (firstNumber + secondNumber).ToString();
isFirstNumberSet = false;
break;
case "ButtonMinus":
TextBox1.Text = (firstNumber - secondNumber).ToString();
isFirstNumberSet = false;
break;
case "ButtonDziel":
TextBox1.Text = (firstNumber / secondNumber).ToString();
isFirstNumberSet = false;
break;
case "ButtonMnoz":
TextBox1.Text = (firstNumber * secondNumber).ToString();
isFirstNumberSet = false;
break;
}
but when i do for example action like 2 + 2, and after that i hit "=". I get an exception about that code:
switch (lastClicked.ID)
It says that lastClicked is null, but how? after hit "+" this should save sender object to this variable. Am i wrong?
Your button variable assignment does not persist between postbacks the way you are expecting. When calculate fires upon your "=" keyhit, lastClicked is now unassigned on this new "round trip," and thus null. When you press one button once, then a second button the next time, there's no memory of the previous hit unless you store the value in a field that's captured in the data sent back to the server.
One approach you could explore involves storing the operation that's been selected into a hidden HTML field on your form, and then interrogate that upon hitting the calculate routine. That eliminates the need to try persisting the "lastClicked" button as you have.
Somewhere in your aspx, within your form, you could add:
<asp:HiddenField id="Operation" runat="server" />
Then, in your codebehind in response to one of your operator buttons:
Operation.Value = "Plus"; // or "+" or whatever is appropriate
That would then get sent back down to the client on the next trip, and then be part of the data sent back to the server when your calculate method is called in response to the "=" button click:
public void calculate(object sender, EventArgs e){
switch(Operation.Value){
case "Plus";
// do the "PLUS" thing
// and so on
... (snip)...
}

Wierd behavior while many clients generate cache

I show you my problem by simple code snippet.
This is popular scenario. Users load our page when there is no cache so we generate one. In my code example this take 120 seconds to save cache and before this i inrement static variable.
My qustion is why static variable "i" doesn't increment when i open this page many times in the same moment and cache is null.
public partial class _Default : Page
{
static int i = 0;
protected void Page_Load(object sender, EventArgs e)
{
int i;
var cache = Cache.Get("cache") as string;
if (string.IsNullOrEmpty(cache))
{
i = GenerateCache();
}
else
{
i = Convert.ToInt32(cache);
}
Response.Write(i.ToString());
}
public int GenerateCache()
{
var sw = new Stopwatch();
sw.Start();
++i;
Response.Write(i+"<br>");
while (sw.ElapsedMilliseconds < 1000 * 120) { }
Cache.Insert("cache", i.ToString());
return i;
}
}
Because you have a bug by declaring again the i on the PageLoad
protected void Page_Load(object sender, EventArgs e)
{
int i; // <----- here, this is probably bug and you must remove this line
also you need some kind of locking to avoid multiple calls at the same moment, even tho you saved by the lock of the page session for the moment.

Posting data between Asp.Net Web Pages

I have a list of strings, which are generated on a imagebutton_click method. I want to be able to use this list in another webpage.
How ever im not quite sure how to go about posting it between the two pages.
I have the following code below:
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
RadGrid rg = RadGrid1;
//Get selected rows
GridItemCollection gdc = (GridItemCollection)rg.SelectedItems;
foreach (GridItem gi in gdc)
{
if (gi is GridDataItem)
{
GridDataItem gdi = (GridDataItem)gi;
if (!string.IsNullOrEmpty(gdi["Email"].Text))
{
string client = gdi["Email"].Text;
//Creating a List of Clients to be Emailed
emailList.Add(email);
}
}
//Enable the Prepare Email Page
PageView2.Selected = true;
}
protected void ImageButton2_Click(object sender, ImageClickEventArgs e)
{
if (emailList.Count != 0)
{
for (int i = 0; i < emailList.Count; i++)
{
_to = emailList[i].ToString() + ";";
}
}
else
{
_to = emailList[1].ToString();
}
//Processing Client Email
string _from = sec.GetCurrentUserEmail("test");
string _cc = "";
string _subject = SubjectTB.Text;
string _body = EmailEditor.Content;
string _tempTo = sec.GetCurrentUserEmail("temp");
string _msg = sec.SendMail(_tempTo, _cc, _from, _subject, _body, "");
if (_msg == "success")
{
//Thank the user and record mail was delivered sucessfully
TestPanel.Visible = true;
}
}
How do I get the values of emailList to be passed through to ImageButton2_click(object sender, ImageClickEventArgs e). Currently it just passes through a null value. I gather I need to use HTML forms to do the request. Thanks.
I'm guessing that emailList is a private variable? Wouldn't you be able to add that to the LoadControlState and SaveControlState so that it'll be available for ImageButton2_Click later?
Here is an example: http://msdn.microsoft.com/en-us/library/system.web.ui.control.loadcontrolstate%28v=vs.80%29.aspx
Another possibility is hidden field, that might be the simplist way, but not as secure.
You can get a good idea about state management in ASP.Net here. For your case if button1 and button2 are in the same aspx page, Viewstate would be a good idea. If they are in diferent pages then use Session state management.

Textbox value null when trying to access it

namespace Dynamic_Controls.Dropdowndynamic
{
public partial class DropdowndynamicUserControl : UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
if (ControlCount != 0)
{
Recreatecontrols();
}
}
private void Recreatecontrols()
{
// createtextboxes(ControlCount);
createtextboxes(2);
}
protected void createtextboxes(int ControlCount)
{
DynPanel.Visible = true;
for (int i = 0; i <= ControlCount; i++)
{
TextBox tb = new TextBox();
tb.Width = 150;
tb.Height = 18;
tb.TextMode = TextBoxMode.SingleLine;
tb.ID = "TextBoxID" + this.DynPanel.Controls.Count;
tb.Text = "EnterTitle" + this.DynPanel.Controls.Count;
tb.Load+=new EventHandler(tb_Load);
tb.Visible = true;
tb.EnableViewState = true;
DynPanel.Controls.Add(tb);
DynPanel.Controls.Add(new LiteralControl("<br/>"));
}
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
Int32 newControlCount = Int32.Parse(DropDownList1.SelectedValue);
//createtextboxes(newControlCount);
//ControlCount+=newControlCount;
createtextboxes(2);
}
protected void Button1_Click(object sender, EventArgs e)
{
readtextboxes();
}
public void readtextboxes()
{
string x = string.Empty;
for (int a = 0; a < DynPanel.Controls.Count; a++)
{
foreach (Control ctrl in DynPanel.Controls)
{
if (ctrl is TextBox)
{
x = ((TextBox)ctrl).Text;
}
x+=x+("\n");
}
Result.Text = x;
}
}
private Int32 ControlCount
{
get
{
if (ViewState["ControlCount"] == null)
{
ViewState["ControlCount"] = 0;
}
return (Int32)ViewState["ControlCount"];
}
set
{
// ViewState["ControlCount"] = value;
ViewState["ControlCount"] = 2;
}
}
private void tb_Load(object sender, EventArgs e)
{
LblInfo.Text = ((TextBox)sender).ID + "entered";
}
}
}
Are you adding these controls dynamically in Page_Load (by, I'm assuming, calling your AddRequiredControl() method)? If so, is it wrapped in a conditional which checks for IsPostBack? The likely culprit is that you're destructively re-populating the page with controls before you get to the button click handler, so all the controls would be present but empty (as in an initial load of the page).
Also, just a note, if you're storing each control in _txt in your loop, why not refer to that variable instead of re-casting on each line. The code in your loop seems to be doing a lot of work for little return.
You need to recreate any dynamically created controls on or before Page_Load or they won't contain postback data.
I'm not entirely clear what happens on DropdownList changed - are you trying to preserve anything that has been entered already based on the textboxes previously generated?
In any event (no pun intended) you need to recreate exactly the same textboxes in or before Page_Load that were there present on the postback, or there won't be data.
A typical way to do this is save something in ViewState that your code can use to figure out what to recreate - e.g. the previous value of the DropDownList. Override LoadViewState and call the creation code there in order to capture the needed value, create the textboxes, then in the DropDownList change event, remove any controls that may have been created in LoadViewState (after of course dealing with their data) and recreate them based on the new value.
edit - i can't figure out how your code works now, you have AddRequiredControl with parameters but you call it with none. Let's assume you have a function AddRequiredControls that creates all textboxes for a given DropDownList1 value, and has this signature:
void AddRequiredControls(int index)
Let's also assume you have a PlaceHolder called ControlsPlaceholder that will contain the textboxes. Here's some pseudocode:
override void LoadViewState(..) {
base.LoadViewState(..);
if (ViewState["oldDropDownIndex"]!=null) {
AddRequiredControls((int)ViewState["oldDropDownIndex"]);
}
}
override OnLoad(EventArgs e)
{
// process data from textboxes
}
void DropDownList1_SelectedIndexChanged(..) {
ControlsPlaceholder.Controls.Clear();
AddRequiredControls(DropDownList1.SelectedIndex);
ViewState["oldDropDownIndex"]=DropDownList1.SelectedIndex;
}

How to log POSTed forms submissions?

Back in the ASP classic days when i needed to write out the name/value pairs of forms submitted by POST i thru this loop into the page:
on error resume next
for each x in Request.Form
Response.AppendToLog x & "=" & Request(x)
next
It threw all the form fields and values into the log just as GETs are. Does IIS7 .net give me any better method? (this is for the dev/testing portion of the project i don't have any concern about the space or cycles used to accomplish this).
thx
You can create an http module to log all posts. It allows you to log outside of the pages, a single point of logging instead of having to add the logic to all pages where you want to log activity.
Here you have some of the code. You would have to avoid logging viewstate since is tons of useless information. So you have to add some logic to achieve this.
public class ActivityLogModule: IHttpModule
{
public void Init(HttpApplication application)
{
application.EndRequest += (new EventHandler(this.Application_EndRequest));
}
private void Application_EndRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
if (RecordActivity(context))
{
ActivityLogger.Instance.Log(application.Context.User.Identity.Name,
application.Context.Request.Url.AbsoluteUri,
application.Context.Request.Form.ToString());
}
}
public void Dispose(){}
protected bool RecordActivity(HttpContext context)
{
if (!context.Request.RequestType.Equals("POST"))
{
return false;
}
return true;
}
}
You could have something like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
LogPostValues();
}
private void LogPostValues()
{
string logPath = #"C:\PostedValuesLog.txt";
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Logging: {0}", Request.Path);
sb.Append("Form Values");
foreach (string key in Request.Form)
{
string val = Request.Form[key];
sb.AppendFormat("{0} = {1}<br/>", key, val);
}
sb.Append(Environment.NewLine);
sb.Append("QueryString Values");
foreach (string key in Request.QueryString)
{
string val = Request.QueryString[key];
sb.AppendFormat("{0} = {1}<br/>", key, val);
}
sb.Append(Environment.NewLine);
sb.Append(Environment.NewLine);
sb.Append(Environment.NewLine);
File.AppendAllText(logPath, sb.ToString());
}
This is a crude method though and shouldn't really be used in production code. However, as this is just for development & testing, it should suffice to track what data is being posted to your page via the querystring and form.

Resources