Anas Ghanem

ASP.NET from the middle east

Syndication

Sponsors

News


    Subscribe in a reader

March 2009 - Posts

Hi All,

The training kit includes presentations,labs,demos to help you learn the new asp.net MVC version 1.0 .

To download the kit,follow this link.

more ASP.NET MVC resources can be found at http://www.asp.net/mvc/
Posted by anas | with no comments
Filed under:

If you used the FormView control ,I’m sure that you had modified it’s generated Edit and Insert templates(like adding calendar for the date fields , changing the textboxes that are bound to the foreign key columns with a dropdown list,adding validation controls to some of the fields , apply some masks … etc .

The Problem:

The problem is that if you need to use edit and insert functionalities in the FormView control, you will have to modify both of it’s edit and insert templates.also will you need to make sure that any change on one of the templates  will be reflected on the other templates.

Consider the following example:

You are working with the orders table of the Northwind database and you want to use the FormView control to add/edit order information's.

The FormView Edit and Insert templates will looks like this (assume you added calendar extender to the data fields) :

<asp:FormView ID="FormView1" runat="server">
    <EditItemTemplate>
=>  Edit template  markup here ...
        <asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update"
            Text="Update" />
        &nbsp;<asp:LinkButton ID="UpdateCancelButton" runat="server" CausesValidation="False"
            CommandName="Cancel" Text="Cancel" />
    </EditItemTemplate>
    <InsertItemTemplate>
 =>    insert template  markup here ...(same as edit template markup)
        <asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert"
            Text="Insert" />
        &nbsp;<asp:LinkButton ID="InsertCancelButton" runat="server" CausesValidation="False"
            CommandName="Cancel" Text="Cancel" />
    </InsertItemTemplate>
</asp:FormView>

As you may noticed, The Edit and Insert templates both contains the same code.As an experienced developer, you should always avoiding duplicate code.This is to increase the maintainability of the code.

 

The Solution: 

There is many solutions for the mentioned problem ,Assume that you are using the FormView to edit/add northwind order object.To avoid duplicating the same markup in both templates , you can move the shared markup from the FormView Edit and Insert templates to a separate usercontrol and place this usercontrol in both templates.

Something like this :

1 <EditItemTemplate>
2 <uc1:OrderEditFields ID="OrderEditFields1" runat="server" />
3 <asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update"
4 Text="Update" />
5 &nbsp;<asp:LinkButton ID="UpdateCancelButton" runat="server" CausesValidation="False"
6 CommandName="Cancel" Text="Cancel" />
7 </EditItemTemplate>
8 <InsertItemTemplate>
9 <uc1:OrderEditFields ID="OrderEditFields1" runat="server" />
10 <asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert"
11 Text="Insert" />
12 &nbsp;<asp:LinkButton ID="InsertCancelButton" runat="server" CausesValidation="False"
13 CommandName="Cancel" Text="Cancel" />
14 </InsertItemTemplate>

Of course,The OrderEditFields UserControl code will contains the code that was moved from the FormView Edit /Insert templates ( but without the command buttons which are different for each template)

1 OrderID:
2 <asp:Label ID="OrderIDLabel1" runat="server" Text='<%# Eval("OrderID") %>' />
3 <br />
4 CustomerID:
5 <asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="SqlDataSource1"
6 DataTextField="CompanyName" DataValueField="CustomerID" SelectedValue='<%# Bind("CustomerID") %>'>
7 </asp:DropDownList>
8 <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
9 SelectCommand="SELECT [CustomerID], [CompanyName] FROM [Customers]" ></asp:SqlDataSource>
10 <br />
11 EmployeeID:
12 <asp:DropDownList ID="DropDownList2" runat="server" DataSourceID="SqlDataSource2"
13 DataTextField="FullName" DataValueField="EmployeeID" SelectedValue='<%# Bind("EmployeeID") %>'>
14 </asp:DropDownList>
15 <asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
16 SelectCommand="SELECT EmployeeID, FirstName + ' ' + LastName AS FullName FROM Employees">
17 </asp:SqlDataSource>
18 <br />
19 OrderDate:
20 <asp:TextBox ID="OrderDateTextBox" runat="server" Text='<%# Bind("OrderDate") %>' />
21 <AjaxToolkit:CalendarExtender ID="OrderDateTextBox_CalendarExtender" runat="server"
22 Enabled="True" TargetControlID="OrderDateTextBox">
23 </AjaxToolkit:CalendarExtender>
24 <br />
25 RequiredDate:
26 <asp:TextBox ID="RequiredDateTextBox" runat="server" Text='<%# Bind("RequiredDate") %>' />
27 <AjaxToolkit:CalendarExtender ID="RequiredDateTextBox_CalendarExtender" runat="server"
28 Enabled="True" TargetControlID="RequiredDateTextBox">
29 </AjaxToolkit:CalendarExtender>
30 <br />
31 ShippedDate:
32 <asp:TextBox ID="ShippedDateTextBox" runat="server" Text='<%# Bind("ShippedDate") %>' />
33 <AjaxToolkit:CalendarExtender ID="ShippedDateTextBox_CalendarExtender" runat="server"
34 Enabled="True" TargetControlID="ShippedDateTextBox">
35 </AjaxToolkit:CalendarExtender>
36 <br />
37 ShipVia:
38 <asp:TextBox ID="ShipViaTextBox" runat="server" Text='<%# Bind("ShipVia") %>' />
39 <br />
40 Freight:
41 <asp:TextBox ID="FreightTextBox" runat="server" Text='<%# Bind("Freight") %>' />
42 <br />
43 ShipName:
44 <asp:TextBox ID="ShipNameTextBox" runat="server" Text='<%# Bind("ShipName") %>' />
45 <br />
46 ShipAddress:
47 <asp:TextBox ID="ShipAddressTextBox" runat="server" Text='<%# Bind("ShipAddress") %>' />
48 <br />
49 ShipCity:
50 <asp:TextBox ID="ShipCityTextBox" runat="server" Text='<%# Bind("ShipCity") %>' />
51 <br />
52 ShipRegion:
53 <asp:TextBox ID="ShipRegionTextBox" runat="server" Text='<%# Bind("ShipRegion") %>' />
54 <br />
55 ShipPostalCode:
56 <asp:TextBox ID="ShipPostalCodeTextBox" runat="server" Text='<%# Bind("ShipPostalCode") %>' />
57 <br />
58 ShipCountry:
59 <asp:TextBox ID="ShipCountryTextBox" runat="server" Text='<%# Bind("ShipCountry") %>' />
60

 

Hope it Helps

Posted by anas | 4 comment(s)
Filed under:

This post contains some of the most asked questions when using login control.

1- how to redirect users to different pages based on their roles.

This can be done by handling the LoggedIn event of the Login control.

protected void Login1_LoggedIn(object sender, EventArgs e) {
// if there is no returnUrl in the query string , we redirect based on user role
if (string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))
{
// please don't use User.IsInRole here , because it will not be populated yet at this stage.
if (Roles.IsUserInRole(Login1.UserName, "Admins"))
Response.Redirect(
"~/Admins/Default.aspx");
else if (Roles.IsUserInRole(Login1.UserName, "Editors"))
Response.Redirect(
"~/Editors/Default.aspx");
}
}

2- how to hide the login control for the logged in users ?

To hide the login control for the logged in users , set it’s VisibleWhenLoggedIn property to false.

<asp:Login ID="Login1" runat="server" VisibleWhenLoggedIn="False" …

You can also use the LoginView control to accomplish that :

<asp:LoginView ID="LoginView1" runat="server">
<AnonymousTemplate>
<asp:Login ID="Login1" runat="server">
</asp:Login>
</AnonymousTemplate>
</asp:LoginView>

 

3-How to hide “remember me next time” checkbox ?

You may need to prevent the users from checking “remember me next time” checkbox to prevent crating a persistent authentication cookie.

To do that , you just need to set it’s DisplayRememberMe property to “false” and then you need to set it’s RememberMeSet property.

If you want to force the website to remember the users , you set the RememberMeSet property to true, else you set it to false.

<asp:Login ID="Login1" runat="server" DisplayRememberMe="false" RememberMeSet="false" …

4-How to use the login control with my existing users table ?

By default,Login control will use the membership provider to validate users credentials , but if you already have your custom users table ,

you can use the login control like this :

protected void Login1_Authenticate(object sender, System.Web.UI.WebControls.AuthenticateEventArgs e)
{
string userName = Login1.UserName;
string password = Login1.Password;

bool result = UserLogin(userName, password);
if ((result))
{
e.Authenticated
= true;
}
else
{
e.Authenticated
= false;
}
}

private bool UserLogin(string userName, string password)
{

// read the coonection string from web.config
string conString = ConfigurationManager.ConnectionStrings["ConnectionStringName"].ConnectionString;

using (System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(conString))
{
//' declare the command that will be used to execute the select statement
SqlCommand com = new SqlCommand("SELECT UserName FROM Users WHERE UserName = @UserName AND Password = @Password", con);

// set the username and password parameters
com.Parameters.Add("@UserName", SqlDbType.NVarChar).Value = userName;
com.Parameters.Add(
"@Password", SqlDbType.NVarChar).Value = password;

//' execute the select command
try
{
con.Open();
//' execute the select statment
string result = Convert.ToString(com.ExecuteScalar());
//' check the result
if (string.IsNullOrEmpty(result))
{
//invalid user/password , return flase
return false;
}
else
{
// else return true , valid login
return true;
}
}
catch (Exception ex)
{
throw;
}
}
}

5-I don’t want the login control to render as html table , instead i want it to render as div , how to do that ?

You can use the CSS friendly control adapters , check this link.

6- I’m getting invalid login after i published my website , the user name and password was working locally , what’s the problem ?

One possible reason is the applicationName in membership configuration, check this link for more information .

7-After i published my website , I’m getting System.Web.Security.SqlMembershipProvider'

requires a database schema compatible with schema version '1'  .. error ,what to do ?

One possible reason is that the published version of  "aspnet_SchemaVersions" table doesn't have the correct values ,

please make sure that it have the values like below :

FeatureCompatibleSchemaVersion  IsCurrentVersion
common

1

TRUE
health monitoring

1

TRUE
membership

1

TRUE
personalization

1

TRUE
profile

1

TRUE
role manager

1

TRUE

8-How to display the login in popup ?

http://weblogs.asp.net/lkempe/archive/2007/01/28/login-control-in-an-asp-net-ajax-toolkit-popupcontrolextender-with-a-close-button.aspx

9- How can i log the invalid login attempts ?

You can handle the LoginError event of the login control :

protected void Login1_LoginError(object sender, EventArgs e)
{
// here you can login the invalid attempts
string UserName = Login1.UserName;
string Password = Login1.Password;
// log the attempt

}

10-I specified my website users inside the credential section in web.config , can i still use the login control ?

Yes you can , you just need to handle the login control authenticate event .

Assume you have this Credential section in web.config :

<authentication mode="Forms">
<forms>
<credentials passwordFormat="Clear">
<user name="User1" password="****" />
<user name="User2" password="****" />
</credentials>
</forms>
</authentication>

You can let the login control use the mentioned section like this :

protected void Login1_Authenticate(object sender, System.Web.UI.WebControls.AuthenticateEventArgs e)
{
string UserName = Login1.UserName;
string Password = Login1.Password;

if (FormsAuthentication.Authenticate(UserName, Password))
{
e.Authenticated
= true;
}
else
{
e.Authenticated
= false;
}
}

The FormsAuthentication.Authenticate method will automatically check users against the credential section.

11- I'm not using FormsAuthenticaiton, instead I'm using the session object to secure my website , can i still use the login control ?

Yes , you can; please read my post about this.

Hope it helps.

Posted by anas | 1 comment(s)

Mike Swanson summarized the various options to download the Mix 09 videos and keynotes , Read his post [here].

Posted by anas | with no comments
Filed under:

Implementing output cache for the GridView is straight forward if the GridView doesn't require to provide paging functionality.

And so , if you don't need paging in the GridView , you can set the output cache on the page level and the GridView will be cached like any other control on the page.

However,the mentioned solution will not work if you tried to enable paging in the GridView , because the user will not be able to navigate to the other pages because page output cache is enabled.

There is many suggestions to the mentioned problem:

The first suggestion is to use the ListView control and configure it's pager control to use the Query string for passing page index,for more information about this solution ,read my post [here].

The second suggestion is to avoid using output cache on the page level, and just set the cache on the data source level ( by setting data source Enable Caching property to true).This will of course cache the data and not the GridView html output.This is a good solution to avoid hitting the database every time the user open the page.read more on how to use caching with data source controls [here]

The Third suggestion  is to use a user control and cache it's output using output cache, this will also require to vary the output cache of the user control based on the GridView page index.So that you will have a separate cached version of the user control for each GridView page.

To implement this solution , set the output cache directive in the user control:

<%@ OutputCache Duration="90" VaryByControl="HiddenField1"  %>

This will enable output cache on the user control for 90 seconds and will create a separate cached  version of the user control for each hidden Field (HiddenField1) value.

You need then to set the HiddenField value based on the Selected page index , something like this :

 

Protected Sub GridView1_PageIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles GridView1.PageIndexChanged
HiddenField1.Value
= GridView1.PageIndex
End Sub

For more information about output cache directive , see this link.

 

Anas Ghanem

Posted by anas | 2 comment(s)
Filed under: , ,
More Posts