Wednesday, October 25, 2006

Tuning and performance tips for ASP.NET 2.0

A great article that shows some major tips in ensuring your application is running at its maximum peak!

Enhancing the Profile object with a custom profile provider

One of the downsides of the profile object is that in its default state it pushes all the data to un accessable columns in the profile tables.

I need to access the data in the profile object in the sql queries. So the only way to do this is to create my own profileprovider (the data into the datastore goes via this new provider)

Guess what, there is already prewritten profile providers out there that will do this for me :).

Heres the link to a Microsoft guy Hao Kung thats done the hard work for us. He's documented out a tableprofileprovider for us and given us his code and notes! What a guy. Link to the samples and the whitepaper can be found here.

Profile and storing a shopping cart

So i want to build a shopping cart into my ecommerce site..

This is how i implemented it...


1) created a shopping cart and shopping cart item concept clases (see this blog entry "generics - shopping cart" for the design of the classes)

2) Because the shopping cart is at the level of the user im gonna use the Profile object to store it. A huge advantage of the Profile architecture is that it is generic enough to allow me to store arbitary types and supports a multitude of persistence methods. In my case im gonna store the persisted class into the profile object.. awesome!


<profile enabled="true">
---<properties>
------<add serializeas="Binary" allowanonymous="true" type="SampleCode.ShoppingCart" name="ShoppingCart">
---</properties>
</profile>


And to use the shopping cart from within code is this simple:

---Profile.ShoppingCart.Items.Add( new Item("Chocolate covered cherries", 3.95F));

Tuesday, October 24, 2006

Monday, October 23, 2006

Calling a webservice from javascript

This is one of the most requested features of ASP.NET Atlas...





By default, Microsoft ASP.NET 2.0 AJAX Extensions
applications cannot call Web services unless explicitly enabled, as explained
below...


1) In the element of the Web site's Web.config file, register the ScriptHandlerFactory class to process calls to .asmx files

---<system.web>
------<httphandlers>
---------<remove path="*.asmx" verb="*">
---------<add type="" path="*.asmx" verb="*">Microsoft.Web.Script.Services.ScriptHandlerFactory" validate="false"/>
------</httphandlers>
---<system.web>

When the proxy class is generated, the proxy class will expose a JavaScript function for each method in the Web service that has been marked with the WebMethod attribute.


2) In the ScriptManager control on the page, define the Web service location by creating an <asp:servicereference> child element and setting its path attribute.


<asp:ScriptManager runat="server" ID="scriptManager">
<services> <asp:servicereference path="~/WebServices/SimpleWebService.asmx" /> </services></asp:ScriptManager>

This setting instructs ASP.NET 2.0 AJAX Extensions where the service is for which to generate a JavaScript proxy.

You can inspect the generated script for the proxy class by entering the following string in the browser address box http://localhost/myService.asmx/js






Setting up the WebService



The web service must be an asmx file and must contain the [ScriptService] attribute . In the sample above we create a webservice file called SimpleWebService.asmx and it will contain the following code...

---[ScriptService]
---public class SimpleWebService : System.Web.Services.WebService{
------[WebMethod]
------public string EchoInput(String input) {
--------- // Method code goes here.
------}
---}





Calling the WebService from JavaScript


sample 1:

function GetNoReturn(){ Samples.AspNet.CallWebService.GetServerTime();}

sample 2:

function GetTime(){
----Samples.AspNet.CallWebService.GetServerTime(OnRequestComplete);
}

function OnRequestComplete(result){
----// Display the result.
----var RsltElem = document.getElementById("Results");
----RsltElem.innerHTML = result;
}

Sample 3:

function Add(a, b){ Samples.AspNet.CallWebService.Add(a, b, OnRequestComplete);}





Client side Error Handling from



function Div(a, b){ Samples.AspNet.CallWebService.Div(a, b, OnRequestComplete, OnRequestFailure);}


function OnRequestFailure(error){
----// Display the error.
----var RsltElem = document.getElementById("Results");
----RsltElem.innerHTML = "Error on the sever: " + error.get_message();
}



For other scenarios see the following link for a more uptodate set of supported scenarios webserviceProxy




Lead by example



The best example explaining all the above can be found here









Sample ASP.NET Atlas project




<!--<Snippet1>-->
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Collections.Generic" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Enter New Employees</title>
<script runat="server">
private List<Employee> EmployeeList;

protected void Page_Load()
{
if (!IsPostBack)
{
EmployeeList = new List<Employee>();
EmployeeList.Add(new Employee(1, "Jump", "Dan"));
EmployeeList.Add(new Employee(2, "Kirwan", "Yvette"));
ViewState["EmployeeList"] = EmployeeList;
}
else
EmployeeList = (List<Employee>)ViewState["EmployeeList"];

EmployeesGridView.DataSource = EmployeeList;
EmployeesGridView.DataBind();
}

protected void InsertButton_Click(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(FirstNameTextBox.Text)
String.IsNullOrEmpty(LastNameTextBox.Text)) { return; }

int employeeID = EmployeeList[EmployeeList.Count-1].EmployeeID + 1;

string lastName = Server.HtmlEncode(FirstNameTextBox.Text);
string firstName = Server.HtmlEncode(LastNameTextBox.Text);

FirstNameTextBox.Text = String.Empty;
LastNameTextBox.Text = String.Empty;

EmployeeList.Add(new Employee(employeeID, lastName, firstName));
ViewState["EmployeeList"] = EmployeeList;

EmployeesGridView.DataBind();
EmployeesGridView.PageIndex = EmployeesGridView.PageCount;
}

protected void CancelButton_Click(object sender, EventArgs e)
{
FirstNameTextBox.Text = String.Empty;
LastNameTextBox.Text = String.Empty;
}

[Serializable]
public class Employee
{
private int _employeeID;
private string _lastName;
private string _firstName;

public int EmployeeID
{
get { return _employeeID; }
}

public string LastName
{
get { return _lastName; }
}

public string FirstName
{
get { return _firstName; }
}

public Employee(int employeeID, string lastName, string firstName)
{
_employeeID = employeeID;
_lastName = lastName;
_firstName = firstName;
}
}

</script>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true" />
<table>
<tr>
<td style="height: 206px" valign="top">
<asp:UpdatePanel ID="InsertEmployeeUpdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<table cellpadding="2" border="0" style="background-color:#7C6F57">
<tr>
<td><asp:Label ID="FirstNameLabel" runat="server" AssociatedControlID="FirstNameTextBox"
Text="First Name" ForeColor="White" /></td>
<td><asp:TextBox runat="server" ID="FirstNameTextBox" /></td>
</tr>
<tr>
<td><asp:Label ID="LastNameLabel" runat="server" AssociatedControlID="LastNameTextBox"
Text="Last Name" ForeColor="White" /></td>
<td><asp:TextBox runat="server" ID="LastNameTextBox" /></td>
</tr>
<tr>
<td></td>
<td>
<asp:LinkButton ID="InsertButton" runat="server" Text="Insert" OnClick="InsertButton_Click" ForeColor="White" />
<asp:LinkButton ID="Cancelbutton" runat="server" Text="Cancel" OnClick="CancelButton_Click" ForeColor="White" />
</td>
</tr>
</table>
<asp:Label runat="server" ID="InputTimeLabel"><%=DateTime.Now %></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
</td>
<td style="height: 206px" valign="top">
<asp:UpdatePanel ID="EmployeesUpdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:GridView ID="EmployeesGridView" runat="server" BackColor="LightGoldenrodYellow" BorderColor="Tan"
BorderWidth="1px" CellPadding="2" ForeColor="Black" GridLines="None" AutoGenerateColumns="False">
<FooterStyle BackColor="Tan" />
<SelectedRowStyle BackColor="DarkSlateBlue" ForeColor="GhostWhite" />
<PagerStyle BackColor="PaleGoldenrod" ForeColor="DarkSlateBlue" HorizontalAlign="Center" />
<HeaderStyle BackColor="Tan" Font-Bold="True" />
<AlternatingRowStyle BackColor="PaleGoldenrod" />
<Columns>
<asp:BoundField DataField="EmployeeID" HeaderText="Employee ID" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
<asp:BoundField DataField="FirstName" HeaderText="First Name" />
</Columns>
<PagerSettings PageButtonCount="5" />
</asp:GridView>
<asp:Label runat="server" ID="ListTimeLabel"><%=DateTime.Now %></asp:Label>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="InsertButton" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
</td>
</tr>
</table>
</form>
</body>
</html>
<!--</Snippet1>-->