DataList control tree and accessing the header and footer – level 300

Recently I converted a DataGrid to a DataList because I decided that I didn’t want my two pieces of data in different table cells.  After converting it to a DataList, I ran into an issue setting the Header text and Footer text programmatically.  I had my HeaderTemplate with a asp:Literal in there.  From my code, I expected to be able to do DataList.Header.FindControl(), but Header isn’t a property, and the HeaderTemplate property is just the interface definition. 


1.  The control doesn’t even exist until the DataList.DataBind() method is run.


2.  Looking at the control tree in the trace, I find that it renders as DataList:_ctl0:myControl for the Header and DataList:_ctl{Count-1}:myControl for the Footer.


3.  To make it work, I have to use DataList.Controls[0].FindControl(”myControl”) for the header and DataList.Controls[Count – 1].FindControl(”myControl”).


So what is the reliable way to get the Header and Footer.  Especially for the footer, I have to get the last control in the Controls collection.  The header and footer should be separate from the rest of the bound list, but that, apparantly, is the case.


I would prefer a more elegant solution and one that is more like the rest of the classes in the .Net Framework.  For instance, the Header and Footer should be able to accept and ID property for control naming.  Better yet, they should be properties of the DataList, but since they don’t exist until runtime, we should at least be able to FindControl(”HeaderID”) at runtime, so the ID property would solve that.


Another quirk in the ASP.NET controls, but there is a workaround.

Explanation of dynamic ASPX compilation and recompilation – level 300

To expand on the topic started in my previous post, here is an overview on how ASP.NET compiles and recompiles assemblies. 


You all know that when you initially make an .aspx page and run it, the application is started and your stuff is compiled into cached assemblies stored by default in C:WINNTMicrosoft.NETFrameworkv1.1.4322Temporary ASP.NET Files#AppName#.  If you keep Win Explorer open to that directory while you restart your app, you’ll see the new temporary files appear as the app is compiled for the first time.  Then for every subsequent request, those files don’t change.  Then change ANYTHING in an .aspx file (even just one character in the markup).  Actually, you don’t have to change anything, just save it again.  As soon as you save it, the cached assembly for that page will be invalidated, and when you hit the page with the browser again, it will be recompiled, and you will see new files pop up, and the old ones will have “.delete” appended.  On the next app restart, the .delete files will be purged.  So to clarify my previous post, ASP.NET does NOT check for changes on every page hit.  It checks for a cached assembly and uses it if it exists.  When a file is saved, the cached assembly is invalidated, so when the page is requested, it doesn’t find a valid assembly, so it must compile it. 


So regarding the previous post, whether you use inline code, code-behind, code-beside, base page inheritence, or a mixture of all of them, the page compilation will have the same behavior, and the request lifecycle will also be the same.  There is no performance difference based on the method in which you code.

Before you can do ASP.NET, you must know Html and JavaScript (CSS doesn’t hurt either) – level 100

I’m not going to make this post a rant, but for anyone readers who are new to ASP.NET and have not come from Website development or ASP, there are some prerequisites to ASP.NET.  ASP.NET is a server-side technology that dynamically emits Html and JavaScript.  Now, you can stumble through an ASP.NET HelloWorld sample without knowing any web technologies, but you won’t be able to do anything with it afterwards.  The Microsoft ASP.NET newsgroup is full of people who ask questions about “ASP.NET”, but their question is really about Html, script or CSS.  For instance: “How can I set focus to a textbox on load of the page in ASP.NET?”  That has NOTHING to do with ASP.NET.  It’s simply running some script on the body’s onLoad event.  So the point I want to get accross is to isolate in your mind the Html, script and CSS from ASP.NET, and make sure you know the web front end before you dive into ASP.NET.

IE 5 & 6 Xml databinding – level 300

The following is not a .Net topic.  It’s an Internet Explorer 5 topic.  The following technique can be used with any web page that uses IE 5+ as the client, so I’ve used it with .html, .asp, and .aspx files.  It’s client-side xml databinding with Internet Explorer.  This feature isn’t in Mozilla, but if you have an IE Intranet app, this is a possible way in which you can make your front end more responsive and flexible. 


If you weren’t away, you can embed a section of xml in a web page, add some attributes to some html controls, and IE will automatically duplicate your bound controls for as many nodes as exist in the xml fragment.  There are events that are thrown throughout the binding process, so you can use JavaScript or VBScript to make the front end dynamic.  The following is a simple binding example:


<html>



<xml id=”xml”>



<MyData>



      <Node>



            <CheckBox>checked</CheckBox>



            <Kount>0</Kount>



      </Node>



      <Node>



            <CheckBox>1</CheckBox>



            <Kount>4</Kount>



      </Node>



      <Node>



            <CheckBox>0</CheckBox>



            <Kount>6</Kount>



      </Node>



</MyData>



</xml>



<body>



<table datasrc=”#xml”>



      <tbody>



            <tr>



                  <td>



                        <input type=”checkbox” id=”chk” datafld=”CheckBox”>



                  </td>



                  <td>



                        <input type=”button” id=”btn” datafld=”Kount”>



                  </td>



            </tr>



      </tbody>



</table>



</body>



</html>



Now, one small issue I ran into was that the property bound in the button is the value property.  The value property is the text on the face of the button, so that won’t due.  I modified it using JavaScript and a <input/> tag event to solve this if I need the button to be disabled if the value isn’t 0.


<html>



<script language=”javascript”>



function changeButton(button){



      if(button.value != “0”){



            button.disabled = true;



      }else{



            button.disabled = false;



      }



      button.onpropertychange = “”;



      button.value = “Delete”;



}



</script>



<xml id=”xml”>



<MyData>



      <Node>



            <CheckBox>checked</CheckBox>



            <Kount>0</Kount>



      </Node>



      <Node>



            <CheckBox>1</CheckBox>



            <Kount>4</Kount>



      </Node>



      <Node>



            <CheckBox>0</CheckBox>



            <Kount>6</Kount>



      </Node>



</MyData>



</xml>



<body>



<table datasrc=”#xml”>



      <tbody>



            <tr>



                  <td>



                        <input type=”checkbox” id=”chk” datafld=”CheckBox”>



                  </td>



                  <td>



                        <input type=”button” id=”btn” datafld=”Kount” onpropertychange=”changeButton(this);”>



                  </td>



            </tr>



      </tbody>



</table>



</body>



</html>

There is NO performance different between code-behind and in-line code. – level 200

I recently had an interesting discussion over lunch with a colleague about the performance of in-line code versus the code-behind model.  I relayed that I prefer to put the small, UI-related code in a <script runat=”server”/> block in the .aspx file, and my colleague swore by the code-behind model.  I currently use the code-behind model because intellisense makes development so much faster, but every time I want to make a small change to the UI that involves som C#, I have to fire up VS.NET and then build the whole project.  For my corporate projects I do this anyway because the of the source control, but not all projects need this.  My colleague insisted that script block incur and extra performance hit because the ASP.NET engine must check for changes in every page hit.  After lunch, I whipped up a test and created to ASP.NET pages:  one with code-behind, and the other with the code in a script block.  I ran each for 1 minute in WAST.  Then I ran each 8 more times.  My results:  It doesn’t make a hill of beans difference.  Each test was less than 1% difference.  Some tests the code-behind was less and 1% faster and some resulted in the in-line code being less than 1% faster.  Averaging all the tests gave the same performance for both methods.  So now I know first-hand that it doesn’t matter architecturally.  It’s only personal  and team preference.  Now, don’t take this as an excuse for putting a lot of code in your .aspx page.  If you choose to do that, it should only be UI event handlers.  All REAL code should be in your business objects.  Use this knowledge responsibly!

Share ASP.NET Context with ASP 2 & 3 – level 400

We all have ASP applications that we need to extend with ASP.NET.  Unless our functionality is wrapped in COM, we may have to rewrite some in .Net.  Wouldn’t it be nice if we could rewrite common app functionality in .Net and then reuse it in the ASP?  I’ve worked up a sample that does just that.  I have a web service that exposes the Session object, so now ASP can query the ASP.NET’s Session object (this method could also be used for the Cache object, Application, etc.).  For this to work, ASP has to be in the same ASP.NET session.  That means that the cookie “ASP.NET_SessionId” must exist on the ASP and ASP.NET side, and it must contain the same session id.  Using the Soap Toolkit v.3, I make the web service calls.  One of the web service methods returns the ASP.NET SessionID.  I use this to manually make a Set-Cookie header in ASP because ASP natively HTML Encodes cookie names (would result in %20, or whatever for the . and the _).  Then in subsequent web service calls, I add a soap header to include the cookie with the ASP.NET session id, and this allows every web service call to participate in the same session, so all the data remains coherant. 


Here is my ASP code:


<%@ Language=VBScript%>



<html>



<body>



<%



set soapclient = CreateObject(“MSSOAP.SoapClient30”)



On Error Resume Next



Call soapclient.mssoapinit(Server.MapPath(“Math.wsdl”))



if err <> 0 then



  Response.Write “initialization failed” + err.description



end if



Dim strASPNETSession



if(Request.Cookies(“ASP.NET_SessionID”) <> “”) Then



      soapclient.ConnectorProperty(“RequestHTTPHeader”) = “COOKIE:” & Request.ServerVariables(“HTTP_COOKIE”)



Else



      strASPNETSession = soapclient.GetASPNET_SessionID()



      soapclient.ConnectorProperty(“RequestHTTPHeader”) = “COOKIE:ASP.NET_SessionID=” & strASPNETSession



End If




Dim a



a = soapclient.GetCookies()



Call Response.AddHeader(“Set-Cookie”, a)



Response.Write(“HTTP_COOKIE Server Variables: “)



Response.Write(Request.ServerVariables(“HTTP_COOKIE”) & “<br><br>”)




Response.Write(“Session Hit Counter = ” & soapclient.SessionHitCounter())




if err <> 0 then



  Response.Write err.description & “<BR/>”



  Response.Write “faultcode=” + soapclient.faultcode & “<BR/>”



  Response.Write “faultstring=” + soapclient.faultstring & “<BR/>”



  Response.Write “FaultActor=” + soapclient.FaultActor & “<BR/>”



  Response.Write “Detail=” + soapclient.Detail & “<BR/>”



end if



%>



</body>



</html>



And my web service code:


[WebMethod(true)]



            public string GetSession(string key)



            {



                  return (string)Session[key];



            }



            [WebMethod(true)]



            public void SetSession(string key, string myValue)



            {



                  HttpContext.Current.Session[key] = myValue;



            }



            [WebMethod(true)]



            public int SessionHitCounter()



            {



                 




                  if (Session[“HitCounter”] == null)



                  {



                        Session[“HitCounter”] = 1;



                  }



                  else



                  {



                        Session[“HitCounter”] = ((int) Session[“HitCounter”]) + 1;



                  }



                  return ((int) Session[“HitCounter”]);



            }



            [WebMethod(true)]



            public string GetASPNET_SessionID()



            {



                  return Context.Request.Cookies[“ASP.NET_SessionId”].Value;



            }



            [WebMethod(true)]



            public string GetCookies()



            {



                  return Context.Request.ServerVariables[“HTTP_COOKIE”];



            }



I was so excited when I got this to work, I had to share.  If you search for this topic on Google, there are thousands of people who have this problem.