Passing parameter to user control inside repeater - asp.net

I have a repeater that lists data including an ID that I pass to a user control that is not visible until I click a linkbutton. However, when I have clicked the linkbutton, the ID has been lost.
Anyone have any idea where I'm going wrong?
Here is the code for the repeater:
<asp:Repeater ID="uxPolicyList" runat="server" onitemdatabound="uxPolicyList_ItemDataBound">
<ItemTemplate>
<tr>
<td class="smaller-ctrl">
<img src="Assets/Images/home-icon.gif" alt="Home Insurance Policy" /><%#Eval("PolicyNumber")%>
</td>
<td>
<%#Eval("StartDate","{0:d}")%>
</td>
<td class="center-cell-ctrl">
<%#Eval("Renewal", "{0:d}")%>
</td>
<td class="center-cell-ctrl">
Postcode:<br />
<%#Eval("Postcode")%>
</td>
<td id='<%#Eval("PolicyNumber")%>' class="button-cell">
<asp:LinkButton ID="uxPolicySummaryButton" CssClass="policy-link-ctrl" CommandName="PolicyNumber" CommandArgument='<%#Eval("PolicyNumber")%>' OnCommand="uxPolicySummaryButton_Command" runat="server">Policy summary<br /></asp:LinkButton>
</td>
</tr>
<uc1:PolicySummary ID="uxPolicySummary" PolicyNumber='<%#Eval("PolicyNumber")%>' runat="server" Visible="false" />
</ItemTemplate>
I have these get/set accessors in the user control code-behind, but they're always blank:
public string _policyNumber = string.Empty;
public string PolicyNumber
{
get
{
return _policyNumber;
}
set
{
_policyNumber = value;
}
}
When testing, I hard coded a value in the user control. i.e.
<uc1:PolicySummary ID="uxPolicySummary" PolicyNumber="545545-5454-54545" runat="server" Visible="false" />
...and it worked fine. Any ideas appreciated

try to reassign value of PolicyNumber property inside OnCommand event with the value of CommandArgument
Edit
or save it into HiddenField inside your control
public string PolicyNumber
{
get
{
return MyHiddenField.Value;
}
set
{
MyHiddenField.Value = value;
}
}

I think you might be missing the ViewState backing store.
public string PolicyNumber
{
get { return ViewState["policyNumber"] as string; }
set { ViewState["policyNumber"] = value; }
}

Related

CSRF fix in aspx page

I need the fix for CSRF flaw for aspx page. The code is like this -
ASPX -
<asp:Content runat='server'>
<asp:Panel runat='server'>
<table>
<tr>
<td>Username</td>
<td><asp:TextBox runat="server" ID="Username" autocomplete="off"></asp:TextBox></td>
</tr>
<tr>
<td>Password</td>
<td><asp:TextBox runat="server" ID="Password" TextMode="Password" autocomplete="off"></asp:TextBox></td>
</tr>
<tr>
<asp:Button ID="Submit" runat="server" Text="Submit"
OnClick="SubmitButton_Click" CssClass="Resizable" />
</tr>
</table>
</asp:Panel>
</asp:Content>
ASPX.cs -
protected void SubmitButton_Click(object sender, EventArgs e)
{
//Code here
}
Now while inserting <%# Html.AntiForgeryToken() %> at the top throws error "The server block is not well formed". So how should I proceed with the fix.
You're using webforms here. They already have anti-xsrf set up in the template of the master page (I think it's tucked in with all of the viewstate data).
So as long as you are using a master page then you needn't worry.
If you're not using a master page just build your own using session state, a hidden field and a guid. I've taken the below from http://willseitz-code.blogspot.com/2013/06/cross-site-request-forgery-for-web-forms.html
Your hiddenfield...
<asp:HiddenField ID="antiforgery" runat="server"/>
The code that does the work server side...
public static class AntiforgeryChecker
{
public static void Check(Page page, HiddenField antiforgery)
{
if (!page.IsPostBack)
{
Guid antiforgeryToken = Guid.NewGuid();
page.Session["AntiforgeryToken"] = antiforgeryToken;
antiforgery.Value = antiforgeryToken.ToString();
}
else
{
Guid stored = (Guid) page.Session["AntiforgeryToken"];
Guid sent = new Guid(antiforgery.Value);
if (sent != stored)
{
throw new SecurityException("XSRF Attack Detected!");
}
}
}
}
And finally the following in your Page_Load method in code behind...
AntiforgeryChecker.Check(this, antiforgery);

Retrieve value for selected radiobutton in ListView asp.net

I would like to send a Guid which should be associated with each radio button as eventargs when the user clicks checkout. I was able to achieve this functionality with just a RadioButtonList but I cannot use that here as the rest of the fields are pulled from the database.
There are numerous questions dealing with this type of topic but I could not find one that addresses exactly what I am trying to achieve.
I have the below list
<asp:Content ID="SubscriptionContent" ContentPlaceHolderID="MainContent" ViewStateMode="Enabled" runat="server">
<asp:Panel ID="SubscriptionPanel" CssClass="shopping-cart" ViewStateMode="Enabled" runat="server">
<asp:ListView ID="NewSubscription" runat="server">
<LayoutTemplate>
<table class="table">
<thead>
<th>Select a Subscription</th>
<th>Subscription Level
</th>
<th>Description
</th>
<th>Price
</th>
</thead>
<tbody>
<tr id="itemPlaceholder" runat="server" />
</tbody>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td class="description"><asp:RadioButton ID="SubscriptionLevel" GroupName="SubscriptionRadio" Text='<%# Eval("SubscriptionLevel") %>' runat="server" /></td>
<td class="description"><asp:Label ID="Details" Text='<%# Eval("Details") %>' runat="server"></asp:Label></td>
<td class="price"><asp:Label runat="server" Text='<%# Eval("Price", "{0:C2}") %>'></asp:Label></td>
<asp:TextBox ID="Id" runat="server" Visible="false" Text='<%# Eval("Id") %>' />
</tr>
</ItemTemplate>
</asp:ListView>
<asp:Button ID="Subscribe" CssClass="btn btn-primary" runat="server" Text="<%$ Snippet: Ecommerce/ShoppingCart/CheckoutButtonLabel, Checkout %>" OnClick="BuySubscription" />
<script type="text/javascript">
$(document).ready(function () {
$("input:radio").attr('name', 'SubscriptionRadio');//Override the naming that asp does
});
</script>
</asp:Panel>
</asp:Content>
I am thinking that if I could update a hidden field with the corresponding guid value for each radio button and submit that when the user triggers BuySubscription. I am not sure how to do this though. Ultimately I just want the user to be able to select one of the subscription options and pass that guid back to the function.
Thank you in advance for any input.
The first problem you're going to run into is that ASP.NET gives each <input type="radio" /> a different name, because it's in a different NamingContainer.
You've added some script to try to work around that by changing the name attribute on the client. Unfortunately, this won't work. When you post the form back to the server, ASP.NET will still be looking for a value using the generated name, which won't exist.
The quick and dirty solution would be to update your script to copy the value from the hidden TextBox to the value attribute of the radiobutton. You would then have to use Request.Form["SubscriptionRadio"] to retrieve the value of the selected option:
<ItemTemplate>
<tr>
<td class="description">
<asp:RadioButton ID="SubscriptionLevel" runat="server"
GroupName="SubscriptionRadio"
Text='<%# Eval("SubscriptionLevel") %>'
/>
<%-- NB: Can't set Visible="False", otherwise it's not rendered: --%>
<asp:TextBox ID="Id" runat="server"
Style="display:none;"
Text='<%# Eval("Id") %>'
/>
</td>
...
</tr>
</ItemTemplate>
...
<script>
$(document).ready(function() {
$("input:radio").each(function(){
var me = $(this);
var id = me.closest("tr").find("input[name$=Id]").val();
me.attr("value", id);
me.attr('name', 'SubscriptionRadio');
});
});
</script>
Alternatively, you could use a custom RadioButton control which works within a data-bound control. I posted a simple example back in 2012: https://stackoverflow.com/a/13271444/124386
using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Reflection;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace SiteControls
{
[ToolboxData("<{0}:ListRadioButton runat=\"server\" />")]
public class ListRadioButton : RadioButton
{
private static readonly FieldInfo UniqueGroupNameField = FindUniqueGroupNameField();
private string _uniqueGroupName;
private static FieldInfo FindUniqueGroupNameField()
{
return typeof(RadioButton).GetField("_uniqueGroupName",
BindingFlags.NonPublic | BindingFlags.Instance);
}
public string Value
{
get { return Attributes["value"]; }
set { Attributes["value"] = value; }
}
protected virtual string CreateUniqueGroupName()
{
string result = GroupName;
if (string.IsNullOrEmpty(result))
{
result = ID;
}
if (string.IsNullOrEmpty(result))
{
result = UniqueID;
}
else
{
Control container = NamingContainer;
if (container != null)
{
if (container is IDataItemContainer)
{
container = container.NamingContainer ?? container;
}
result = container.UniqueID + base.IdSeparator + result;
}
else
{
string uniqueID = UniqueID;
if (!string.IsNullOrEmpty(uniqueID))
{
int index = uniqueID.LastIndexOf(base.IdSeparator);
if (index != -1)
{
result = uniqueID.Substring(0, 1 + index) + result;
}
}
}
}
return result;
}
private void EnsureUniqueGroupName()
{
if (_uniqueGroupName == null)
{
string value = CreateUniqueGroupName();
if (UniqueGroupNameField != null) UniqueGroupNameField.SetValue(this, value);
_uniqueGroupName = value;
value = base.Attributes["value"];
if (string.IsNullOrEmpty(value))
{
base.Attributes["value"] = UniqueID;
}
}
}
protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
EnsureUniqueGroupName();
return base.LoadPostData(postDataKey, postCollection);
}
protected override void Render(HtmlTextWriter writer)
{
EnsureUniqueGroupName();
base.Render(writer);
}
}
}
You can either register the control in the page markup:
<%# Register tagPrefix="site" namespace="SiteControls" %>
or in the web.config file:
<?xml version="1.0"?>
<configuration>
<system.web>
<pages>
<controls>
<add
tagPrefix="site"
namespace="SiteControls"
/>
</controls>
</pages>
</system.web>
</configuration>
With that in place, you can lose the script and the hidden TextBox:
<ItemTemplate>
<tr>
<td class="description"><site:ListRadioButton ID="SubscriptionLevel" runat="server"
GroupName="SubscriptionRadio"
Text='<%# Eval("SubscriptionLevel") %>'
Value='<%# Eval("Id") %>'
/></td>
...
To find the selected item, you would then need to loop through the ListView's Items, find the RadioButton control, and look at the Checked property:
ListRadioButton selectedItem = NewSubscription.Items
.Select(item => (ListRadioButton)item.FindControl("SubscriptionLevel"))
.FirstOrDefault(radio => radio != null && radio.Checked);
string selectedValue = (selectedItem == null) ? null : selectedItem.Value;

How can i fetch data of checked checkbox in repeater when click on button?

I have code of repeater like this .Now when i click on button i want job_id of selected checkbox.
`<asp:Repeater ID="rptJob" runat="server" >
<ItemTemplate>
<td valign="middle" style="padding-left: 10px; padding-right: 10px">
<table align="center" cellpadding="0" cellspacing="0" border="0" width="604">
<tr>
<td width="3%" valign="top">
<asp:CheckBox ID="CheckBox1" runat="server" CssClass="search-link"/>
</td>
<td valign="middle" align="left">
<a href="display_job.aspx?jobId=`<%# Eval("job_id")`%>&empId= "` # Eval("emp_id") %>"` target="_blank">
<asp:Label ID="title" runat="server">
<%#DataBinder.Eval(Container.DataItem, "job_title")%> </asp:Label>
</a> </td>
</asp:Repeater>`
In code behind what i have to write on button click event?
There are a number of ways to solve this issue. Assuming the button click causes a postback I'd choose one of the two:
Switch to the ListView control (instead of the Repeater) and utilize this DataKeyNames property. You'll need to add a handler for the CheckBox's CheckChanged event as well. The accepted answer here should be of help in implementing the handler: http://forums.asp.net/t/1581511.aspx/1
Subclass the CheckBox control and add a property to store the job ID. Add a handler for the CheckChanged event (in the handler, cast the sender argument to your newly subclassed checkbox). In the aspx/ascx page, bind the job_id to the newly added property.
[ToolboxData(#"<{0}:JobCheckBox runat=""server""></{0}:JobCheckBox>")]
public class JobCheckBox : CheckBox
{
[Category("Data")]
[DefaultValue(0)]
[Description("The Job ID associated with this checkbox.")]
// Assuming the job ID is an int
public int JobId
{
get { return (ViewState["JobId"] is int) ? (int)ViewState["JobId"] : 0; }
set { ViewState["JobId"] = value; }
}
}

How to read ListView data into generic List

I have a ListView which is filled by generic list of type MyClass. I can easily bind data from this list into ListView. But I have problems with reading data in opposite direction.
This is my class:
public class MyClass
{
public int id { get; set; }
public string name { get; set; }
}
I have also generic list of type MyClass:
List<MyTest> list = new List<MyTest>();
Finally I bind data to ListView this way:
ListView1.DataSource = list;
ListView1.DataBind();
My ListView template:
<asp:ListView runat="server" ID="ListView1">
<LayoutTemplate>
<table runat="server" id="table1" >
<tr runat="server" id="itemPlaceholder" ></tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr id="tr" runat="server">
<td id="td1" runat="server">
<asp:TextBox ID="tb1" runat="server" Text='<%#Eval("id") %>' />
</td>
<td id="td2" runat="server">
<asp:TextBox ID="tb2" runat="server" Text='<%#Eval("name") %>' />
</td>
</tr>
</ItemTemplate>
How can I read data from ListView into my List list?
The operation of reading ListView data into List generic list should begin after clicking the button "GetData"
I can't test this, but I believe this will work:
using System.Linq;
List<MyClass> list = ListView1.DataSource.Cast<MyClass>().ToList();
UPDATE: As noted in the comments, that only works right after you set the DataSource. If you want to get the list on a post-back, try:
List<MyClass> list = ListView1.Items
.Select(lvi=>lvi.DataItem as MyClass)
.ToList();
You can get at the ListViewItem in an updating event like this:
<asp:ListView ID="ListView1" runat="server" OnItemUpdating="ListView1_ItemUpdating"></asp:ListView>
void ListView1_ItemUpdating(Object sender, ListViewUpdateEventArgs e)
{
ListViewItem item = ListView1.Items[e.ItemIndex];
// I think you should also be able to do if you are indeed binding with the type List<MyTest>
List<MyTest> item = (List<MyTest>)ListView1.Items[e.ItemIndex];
}
I can show you other ways if you describe more of what the scenario is that you need to get the data.

Editing in ListView without EditMode on

I have a class
public class MyClass
{
public int id {get; set;}
public string name {get; set;}
}
I store objects of type MyClass in list:
List<MyClass> listOfObjects {get; set;}
I want user to edit data. To display data I am using ListView control - I am binding listOfObject list to ListView:
<asp:ListView runat="server" ID="ListView1">
<LayoutTemplate>
<table runat="server" id="table1" >
<tr runat="server" id="itemPlaceholder" >
</tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr id="tr" runat="server">
<td id="td1" runat="server">
<asp:TextBox ID="tb1" runat="server" Text='<%#Eval("id") %>' />
</td>
<td id="td2" runat="server">
<asp:TextBox ID="tb2" runat="server" Text='<%#Eval("name")%>' />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
So far so good, and everything works fine. I see the data in ListView.
I do not know how I can edit data in ListView without entering EditMode - I do not have Edit button, I have only textboxes to enter new data.
All I want is to bind data edited in textboxes in the opposite direction - into listOfObject list. I have tried many solutions
and nothing was working correctly...
I thought that I can read data this way:
var listItems = ListView1.Items.Cast<ListViewDataItem>().Select(a => new MyClass
{
id = ((TextBox)a.FindControl("tb1")).Text,
name = ((TextBox)a.FindControl("tb2")).Text
}).ToList<>();
but with this I get data which were in textbox before editing...
Help me please, because I have no idea how to make it working
(maybe it would be better to use ObjectDataSource?)
Where do you call the last part of your code? I suppose you have a submit button, do you call that code in it's Click EventHandler?
You must be overwriting your data. If you DataBind in the Page's Load event make sure you only do that if the page is not posting back.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// databind
}
}

Resources