September 2006 - Posts

Meet the Advanced Developers: ADC06 Mannheim/Germany

I am talking on the german ADC about WEB 2.0 with ASP.NET/ATLAS. There are several well known speakers like

  • Steve Cook
  • Christian Weyer
  • Dominick Baier
  • Marcus Heege
  • and others...

So come and see the show there are still some (few) seats left.

 

Posted by preishuber | with no comments
Filed under: , ,

RSS is like Visual Basic: Powerfull and full of danger

It's easy to create and consume RSS with ASP.NET. This is usefull to transport documents without the overhead eg of SOAP. The only problem is that if the implementation is bad ~ 99% increased traffic will be generated.

Consumer can pull the rss frequently and the whole amount of data is transfered again and again.

RSS must have at least two optimizations:

1) Conditional GET

Means that the RSS Data is signed by a value called ETAG. The server transfer this to the client and the client send it back during request. The server send back a HTTP 304 status code if the etag is identical. No rss data is transfered again.

2) HTTP compression

XML is a very overheaded format and can be compressed very effectiv.

With a usal RSS reader or if include a 3rd party RSS in your website you can not see the quality of the rss source. HTTP Fiddler can help to detect that kind of issues.

For easy testing your feed i have implemented a test page.

Try it and give feedback.

I have not made performance test or crash test, but included GZIP decoding.

Posted by preishuber | 1 comment(s)
Filed under:

14 VB 2005 Gridview Samples by Hannes

i collected my 14 best gridview samples which are diging deeper to share it now.

formated Boundfield

If you want to format a column you can do it with a templatefield and the new Eval expression

<%eval("field",formatexpression)%>

or shorter with 2 attributes. Take care on HTMLEncode

<asp:BoundField DataField="OrderDate" HeaderText="OrderDate" SortExpression="OrderDate" DataFormatString="{0:d}" HtmlEncode="False" />

<asp:BoundField DataField="Freight" HeaderText="Freight" SortExpression="Freight" DataFormatString="{0:c}" HtmlEncode="False" />

Paging huge amount of data

Many of ASP.NET developers doesnt know that, on paging all data from the select query is transfered for every page request. You can activate Caching in SQLDatasource to prevent that.

<asp:SqlDataSource ID="SqlDataSource1" runat="server"

EnableCaching CacheDuration=60

Also there exists a new data cache dependency  which allows to update data when the source have changes. But you have still the issue to load the complete data into the cache.

Custom paging can be implemented with objectdatasource. You need a method name for the selection of the data and 2 numbers which controls the page and size.

<asp:GridView AutoGenerateColumns=true PageSize=10

ID="GridView1" runat="server" AllowPaging="True"

DataSourceID="ObjectDataSource1">

</asp:GridView>

<asp:ObjectDataSource ID="ObjectDataSource1"

runat="server"

EnablePaging=true

SelectMethod="GetProducts"

TypeName="ProductDAL"

StartRowIndexParameterName="startIndex"

MaximumRowsParameterName="maxRows"

SelectCountMethod="CountProducts"

></asp:ObjectDataSource>

The dataobject can be stored as source file into the app_code directory. The sample doesnt implement the real kernel of the paging logic.

Imports Microsoft.VisualBasic

Imports System.Configuration

Imports System.Data

Imports System.Data.SqlClient

Imports System.Collections.Generic

Public Class ProductDAL

Public _countproducts As Integer

Public Function GetProducts() As DataSet

Return GetProducts(Integer.MaxValue, 0)

End Function

Public Function GetProducts(ByVal maxRows As Integer, ByVal startIndex As Integer) As DataSet

Dim sql As String = "SELECT ProductID, ProductName, QuantityPerUnit, UnitPrice, UnitsInStock FROM Products"

Using myConnection As New SqlConnection(ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString)

Dim myCommand As New SqlCommand(sql, myConnection)

Dim myAdapter As New SqlDataAdapter(myCommand)

myConnection.Open()

Dim DS As New DataSet

myAdapter.Fill(DS)

_countproducts = DS.Tables(0).Rows.Count

Dim i As Integer = startIndex

Dim itemsRead As Integer = 0

Dim totalRecords As Integer = DS.Tables(0).Rows.Count

Dim dt As New DataTable

dt = DS.Tables(0).Clone

While itemsRead < maxRows AndAlso i < totalRecords

dt.ImportRow(DS.Tables(0).Rows(i))

itemsRead += 1

i += 1

End While

myConnection.Close()

Dim ds2 As New DataSet

ds2.Tables.Add(dt)

Return ds2

End Using

End Function

Public Function CountProducts() As Integer

Return _countproducts

End Function

End Class

Search data

Search can be done very easily with the controlparameter form the sqldatasource. A user types into the string into a textbox. The wizard creates a sql command which includes a WHERE condition.  The problem is that this makes also a lot of traffic and caching doenst solve the problem cause a cache for each query will be stored. There exists a second type to find the data the filterparameter.

<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"

SelectCommand="SELECT [CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address] FROM [Customers] ">

<FilterParameters>

<asp:ControlParameter ControlID="TextBox1" Name="CompanyName" PropertyName="Text"

Type="String" />

</FilterParameters>

</asp:SqlDataSource>

The filtering is done with a attribute.

FilterExpression="companyname like '{0}'"

Now you can cache the data.

Insert Record

Gridview have now default Insert feature. Anyway the wizard of sqldatasource creates the insert command. You can swith to other controls like detailsview or use my approach.

Add a textbox for primarey key and a button to the form. Change the Insert command to insert only the necesarry field like PK.

Click Event: set parameter, call insert, databind to refresh, find new added row

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)

SqlDataSource1.InsertParameters(0).DefaultValue = TextBox1.Text

SqlDataSource1.Insert()

GridView1.DataBind()

Dim dk As DataKey

Dim i As Integer = 0

For Each dk In GridView1.DataKeys

If dk.Value = TextBox1.Text Then

GridView1.EditIndex = i

Exit For

End If

i += 1

Next

End Sub

 

Multirow select

A quite well known sample. I will show it for the complete picture. A Checkbox in any row gives the user the possibility to select the row (Templatefield). A button handles the event to handle the selection.

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)

Dim i As Int16

For i = 0 To GridView1.Rows.Count - 1

If CType(GridView1.Rows(i).FindControl("check"), CheckBox).Checked() Then

Label1.Text += ("-" & GridView1.DataKeys(i).Value.ToString)

End If

Next

End Sub

To check or uncheck all rows with one click, i added another Checkbox in the header of the templatefield.

<asp:TemplateField>

<HeaderTemplate>

<asp:CheckBox ID="Alle" OnClick="BLOCKED SCRIPT return selectAll (this.checked);"

runat="server" />

</HeaderTemplate>

<ItemTemplate>

<asp:CheckBox runat=server ID="check" />

</ItemTemplate>

</asp:TemplateField>

You must use some jscript to do the client job.

<script language=javascript>

function selectAll (alle)

{ var frm = document.forms[0];

for (i=0; i<frm.length; i++)

{if (frm.elements[i].id.indexOf('check') != -1)

{frm.elements[i].checked = alle;

}}}</script>

Calculated row

There are nearly no limitations in templatefields. Also you can call a "external" function to calculate some thing.

<asp:TemplateField HeaderText="summe">

<ItemTemplate>

<%#summe(Eval("unitprice"), Eval("quantity"))%>

</ItemTemplate>

</asp:TemplateField>

Dropdown in gridview edit mode

I have made several postings about the details so i only put the code here.

<asp:TemplateField HeaderText="PostalCode" SortExpression="PostalCode">

<EditItemTemplate>

<asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="DSPLZ" DataTextField="PostalCode"

DataValueField="PostalCode" SelectedValue='<%# Bind("PostalCode") %>'>

</asp:DropDownList>&nbsp;

</EditItemTemplate>

<ItemTemplate>

<asp:Label ID="Label1" runat="server" Text='<%# Bind("PostalCode") %>'></asp:Label>

</ItemTemplate>

</asp:TemplateField>

Nested Master Detail

Following the logic from the previous sample you can handle also a gridview as child control. To control the where condition from the related child table i use a hidden field in the same template.

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="OrderID"

DataSourceID="DSOrders">

<Columns>

<asp:BoundField DataField="OrderDate" HeaderText="OrderDate" SortExpression="OrderDate" />

<asp:BoundField DataField="EmployeeID" HeaderText="EmployeeID" SortExpression="EmployeeID" />

<asp:BoundField DataField="Freight" HeaderText="Freight" SortExpression="Freight" />

<asp:BoundField DataField="OrderID" HeaderText="OrderID" InsertVisible="False" ReadOnly="True"

SortExpression="OrderID" />

<asp:TemplateField>

<ItemTemplate>

<asp:HiddenField ID="HiddenField1" runat="server" Value='<%# Eval("OrderID") %>' />

<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" DataSourceID="DSDetails">

<Columns>

<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" />

<asp:BoundField DataField="Quantity" HeaderText="Quantity" SortExpression="Quantity" />

<asp:BoundField DataField="Discount" HeaderText="Discount" SortExpression="Discount" />

</Columns>

</asp:GridView>

<asp:SqlDataSource ID="DSDetails" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"

SelectCommand="SELECT [UnitPrice], [Quantity], [Discount] FROM [Order Details] WHERE ([OrderID] = @OrderID)">

<SelectParameters>

<asp:ControlParameter ControlID="HiddenField1" Name="OrderID" PropertyName="Value"

Type="Int32" />

</SelectParameters>

</asp:SqlDataSource>

</ItemTemplate>

</asp:TemplateField>

</Columns>

</asp:GridView>

<asp:SqlDataSource ID="DSOrders" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"

SelectCommand="SELECT [OrderDate], [EmployeeID], [Freight], [OrderID] FROM [Orders]">

</asp:SqlDataSource>

Rows with buttons

Not realy a secret: If you add buttons to rows you can make the selection of the button action with the attribute commandname

<asp:ButtonField Text="new order" CommandName="order" ButtonType=Button/>

The Event have as second argument a reference to that command.

Protected Sub GridView1_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs)

Select Case e.CommandName

Case "order"

Label1.Text = "new order for:" + GridView1.DataKeys(e.CommandArgument).Value

End Select

End Sub

Full row select and hovering

During the creation of the gridview you can add functionality in the rowcreated event. In this sample i add Jscript which changes the background color and fires a event for a existing button.

Protected Sub GridView1_RowCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs)

e.Row.Attributes.Add("onMouseOver", "this.style.background='silver'")

e.Row.Attributes.Add("onMouseOut", "this.style.background='white'")

e.Row.Attributes.Add("onClick", "__doPostBack('GridView1','Hannes$" + e.Row.DataItemIndex.ToString + "')")

End Sub

This is a kind of trick which can be figured out if you look at the generated page source.

<asp:ButtonField ButtonType="Button" CommandName="Hannes" Text="&gt;&gt;" />

Show the ordering with image

If you click on a column header user changes the sorting. To show the acutal status i add a arrow image which is named like the ortdirection.

Protected Sub GridView1_RowCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs)

Dim x As Integer

Select Case e.Row.RowType

Case ListItemType.Header

For x = 0 To GridView1.Columns.Count - 1

Dim lb As LinkButton

lb = CType(e.Row.Cells(x).Controls(0), LinkButton)

If lb.CommandArgument = GridView1.SortExpression Then

Dim img As New System.Web.UI.WebControls.Image

img.ImageUrl = GridView1.SortDirection.ToString + ".gif"

e.Row.Cells(x).Controls.Add(img)

End If

Next

End Select

End Sub

Delete Confirmation

<asp:TemplateField ShowHeader="False">

<ItemTemplate>

<asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="False"

CommandName="Delete" OnClientClick="return confirm('are you sure?');"

Text="L”schen"></asp:LinkButton>

</ItemTemplate>

</asp:TemplateField>

(no comment)

CSS Control Adapters

No source code here. But cou can use the CSS control adapters to change the renderd HTML code without changing page or page code.

eg TH instead of TH rendering

(from my point of view this is a kind of bugfixing)

http://www.asp.net/cssadapters/GridView.aspx

Smarter UI (Callback)

Gridview have a atrribute

EnableSortingAndPagingCallbacks

which do this both jobs without a visible postback. Also page have a attribute

MaintainScrollPositionOnPostback

which directs the user to the same position after postback.

Much better is to use ATLAS (now AJAX). You only have to put the gridview into a updatepanel. No more visible postbacks!

 

 

 

 

 

 

Missing ASP.NET Tab in IIS MMC on 64 bit machines

some guy from microsoft blogged about the missing ASP.NET Tab in IIS MMC. On 32 bit systems there are 2 major workarounds ( aspnet_regiis -i and regkey)

It seems that on 64 bit systems its not possible to have this tab. Bug by feature!

http://blogs.msdn.com/carloc/archive/2006/09/09/747702.aspx

 

Posted by preishuber | with no comments
Filed under:
More Posts