Online friends you have never met (not even online)


I was looking through my "spaces" messages and friend requests today and I noticed there are about 15 friend requests from people I do not know. Now, this might seem normal to some people, but I wonder what is compelling people to want to "be my friend". Did they read an entry on my blog that touched their heart? Or, are they trying to gather online friends, as if it is some contest. Or, is it something else?
 
I am a bit more liberal with linking to people on some sites than others, but I don’t think I have added many Internet "friends" whom I had not at least had an online conversation with. Yet, I have 15 people who have not even commented on this blog who want me to be their online friend.
 
If you are one of these people, please understand that I am not rejecting you. I write this blog to push out ideas, most of them insights in computer programming. It is not an attempt to gather online friends. If you are sincere about wanting me to add you, then let’s at least meet. Drop a comment and let’s converse.
 
There is a part of me that wonders what new scam can be perpetuated by adding someone as a friend. It is too much work, I would think, just to get my personal email, but maybe that is it? I am not sure, but I am not adding these people as friends until I meet them. End of story.
 
Now, if you are one who adds a lot of online friends you have not even met online, and see the wisdom in this practice, please drop a comment. I am open to hearing how this is a good thing.
 
Peace and Grace,
Greg

Working with the Flex Framework


This blog entry is about the Flex Framework. I just recently received a project from a vendor. It is written completely in Flex, except for a web service to get data to the application (unnecessary, I have found out, but I do like the SOA patterns, so this one gets kudos).
 
When I got the application, it was configured incorrectly, and everything was hardcoded. I had three things I pushed back on the team:
  1. Pulling from QueryString had to work in all environments
  2. I need to have the maps pulled from a configuration file
  3. I need to be able to set the web service location in configuration

Due to the other projects we have this team on, I ended up doing it myself.

NOTE: This application has to get tings off of the querystring, at least for now, due to constraints in the specifications. It will likely morph into a cleaner FORM post in the future.

Pulling from QueryString in all environments

The original code had the following line:

var params:String = Application.application.parameters.params;

Here is is in context:

public function initComp():void {
       
      var params:String = Application.application.parameters.params;
     
      if (params.length > 0) {
            readParams(params);
            currentState = "showMap";
            mapCont.addMapSource("1" , "lot1.swf", "Lot – 1", "Description for lot 1",
                  new mapPoint(33.934932, -84.174615), new mapPoint(33.930329, -84.16698),
                  980, 634);
           
            mapCont.addMapSource("2" , "lot2.swf", "Lot – 2", "Description for lot 2",
                  new mapPoint(32.847887, -96.865415), new mapPoint(32.84229, -96.857924),
                  863, 767);
                 
      }
      zoomBar.value = 1;
}

This routine is called from the mx:Application tag, which is fairly straightforward Flex. I am fairly certain I have some Flex Framework readers out here that can help me with this one. The line var params:String = Application.application.parameters.params; was not working on my machine. I kept getting a null instead of the value. When I install the application they compiled it works. I did not have a project file, if FlexBuilder creates one, so I did not have any compilation properties, if there are any. Enough of this aside; just ping me if you have an answer.

I went out and found that you can pull from JavaScript by working through a few hoops. First, I needed the routine to grab the querystring, which I found here. Here is the code in the JavaScript:

<script language="JavaScript" type="text/javascript">
      var jsReady = false;
     
function isReady() {
         
return jsReady;
      }
     
function pageInit() {
          jsReady =
true;
      }
     
     
function GetQueryString()
      {
           
var s = window.location.search.substring(1);
           
return s;
      } 
</script>

<
body scroll="no" onLoad="pageInit();">

Easy enough. I am not sure I like search.substring(1), as it is not explicit, but it works fine. Now to my Flex file. First I need an import to use the libraries that pull from JavaScript in the page.

import flash.external.ExternalInterface;

I now needed some code to call the JavaScript routine in action script. The initComp() routine was refactored to avoid having all of the load code. The original is shown above.

public function initComp():void
{
      //Pull the parameters from the querystring
      pullParameters();
      InitConfigLoader();
}

And here is the refactored routines to pull parameters:

private function pullParameters()
{
      params = Application.application.parameters.params;
     
      if(params == null)
      {
            params = EnsureParamsPulledFromQueryString(params);
      }
}

private function EnsureParamsPulledFromQueryString(params:String):String
{
    trace("params are null");
    //Have to run JavaScript for QueryString
    //BABELFISH: Tienen que funcionar el Javascript para QueryString
    var isAvailable:Boolean = ExternalInterface.available;

    //TODO: This should use a timer?
    if(isAvailable)
    {
        if(checkJavaScriptReady())
        {
            params = ExternalInterface.call("GetQueryString");
        }
    }

}

The magic is in the second routine, which fires off the GetQueryString method in JavaScript. Pretty slick, eh? If you want JavaScript to call into Flex, you also need to set up a callback method, but that is beyond what we are doing right now. Here is what happens.

  1. Try to pull parameters from the application object (old code)
  2. If fails, run the pullParameters method and pull from JavaScript GetQueryString
  3. This returns the querystring as a string

Now, this was not good enough for me, as the querystring was in this format:

index.aspx?000000001^vehicle1|000000002^vehicle2|000000003^vehicle3|000000004^vehicle4|000000005^vehicle5|000000006^vehicle6

NOTE: The index.aspx is merely a container at this time. That will change in future iterations.

I am not fond of non-delimited querystring values, as it leaves me no way to add addtional values. As this is not deprecated in the code, I had to leave this alone. The first condition I coded was the normal multi-parameter method of pulling:

    if(params.search("&") > 0)
    {
        //split the string
        //BABELFISH: parta la secuencia
        var splitQueryString:Array = params.split("&");
       
        //Find the correct variable and get rid of ‘vehicles’
        //BABELFISH: Encuentre el variable correcto y líbrese de ‘ vehicles’
        var i:uint;
        for(i=0;1<splitQueryString.length;i++)
        {
            if(splitQueryString[i].substr(0,8) == "vehicles")
            {
                params = splitQueryString[i].toString().replace("vehicles=", "");
                break;
            }
        }
    }

I am fairly certain there is a better syntax here (I could write it shorter in C#, at least), so I am going to learn more Flex to see if I can shorten this up a bit. I am asking here if the string has an ampersand (&), which indicates more than one querystring argument. I then look for the string with vehicles, split it and grab the right hand part of the string. The replace is fairly crude, but it works. This covers this type of string:

index.aspx?debug=true&vehicles=000000001^vehicle1|000000002^vehicle2|000000003^vehicle3|000000004^vehicle4|000000005^vehicle5|000000006^vehicle6

Tested and it works. But what if there is only one argument. It will not find the ampersand, but it will find an equals sign (=). So, I add this condition.

    else if(params.search("=") > 0)
    {
        //See if this is vehicles or something else
        //BABELFISH: Vea si éste es vehículos o algo más
        if(params.substr(0,8) == "vehicles")
        {
            params=params.replace("vehicles=", "");
        }
        else
        {
            params = "";
        }
    }

I have now got something that will pull the string when it is correctly set up as key/value. I also avoid the wrong key, if the single key does not contain the information I want. Any of these URLs yield the correct answer:

index.aspx?000000001^vehicle1|000000002^vehicle2|000000003^vehicle3|000000004^vehicle4|000000005^vehicle5|000000006^vehicle6

index.aspx?vehicles=000000001^vehicle1|000000002^vehicle2|000000003^vehicle3|000000004^vehicle4|000000005^vehicle5|000000006^vehicle6

index.aspx?debug=true&vehicles=000000001^vehicle1|000000002^vehicle2|000000003^vehicle3|000000004^vehicle4|000000005^vehicle5|000000006^vehicle6

And, I have been pessimistic enough that these URLs do not crash anything:

index.aspx
index.aspx?debug=true

One problem solved.

NOTE: As I went to "press" on this, I found that this type of URL could crash the application, so I have to refactor again.

index.aspx?debug=true&

Working with a configuration file

Coming from an ASP.NET world, I use configuration files all of the time. While you cannot change elements on the fly and have the application continue to run without rebooting (not completely true, as you can have your own "config" files), you can customize installs on different machines. What this means, to me, is I can run a variety of like web applications with different skins (configured) and even turn on an off features in config. This is critical to my work, as it stands today, as we produce customized websites with identical funcationality (at least most of it). One engine, multiple sites is a much better option than multiple engines, multiple sites — at least from a maintenance standpoint. Surprised But I digress, as we all know how important configuration is.

As far as I can tell config.xml, the Flex config file, compiles into the application. It is also copied to the output directory, which I do not understand, as I see no way to pull from it at run time. If somebody knows a built in way, let me know. Here is the solution I employed.

I found a blog entry from Ryan Guill which details a component called configLoader (you can find the blog entry here). I included the componet inside my Flex project under the com/util package (create folders and you create package names). Pulling with this is fairly simple. First, you have to pull in import statements to include the package.

import com.util.ConfigLoader;
import com.util.ConfigLoaderEvent;

Next, I have my Init for the config loader.

private function InitConfigLoader()
{
      configLoader = new ConfigLoader("config.xml");
      configLoader.addEventListener(ConfigLoaderEvent.COMPLETE,configLoader_complete_handler);
      configLoader.addEventListener(ConfigLoaderEvent.FAULT,configLoader_fault_handler);
      configLoader.load();
}

Pretty standard. Load the file and careate events to listen to events. This is also straight from the blog page. When it finishes loading, I end up in the routine configLoader_complete_handler, which looks like this:

public function configLoader_complete_handler ( e:ConfigLoaderEvent ) : void
{          
      configXML = e.data; 
      useConfig(configXML);     
}

And, I procede to tear out the XML in the useConfig routine.

public function useConfig( xml:XML ) : void
{
    var i:uint;
    for(i=0;i<xml.maps.map.length();i++)
    {               
        var mapId:String = xml.maps.map[i].ID;
        var source:String = xml.maps.map[i].mapSource;
        var mapName:String = xml.maps.map[i].name;
        var mapDescription:String = xml.maps.map[i].description;
        var ulMapPoint:mapPoint = new mapPoint(xml.maps.map[i].upperLeftLat, xml.maps.map[i].upperLeftLong);
        var lrMapPoint:mapPoint = new mapPoint(xml.maps.map[i].lowerRightLat, xml.maps.map[i].lowerRightLong);
        var x:Number = xml.maps.map[i].imageX;
        var y:Number = xml.maps.map[i].imageY;
       
        mapCont.addMapSource(mapId, source, mapName, mapDescription, ulMapPoint, lrMapPoint, x, y);       
    }   
}

The XML for this routine is here:

<config>
    <webServicePath>http://localhost/MyWebService/webServiceModule.aspx</webServicePath&gt;
    <maps>
        <map>
            <ID>1</ID>
            <name>Lot – 1</name>
            <imageX>600</imageX>
            <imageY>400</imageY>
            <description>Lot 1 Description</description>
            <mapSource>lot1.swf</mapSource>
            <upperLeftLat>33.934932</upperLeftLat>
            <upperLeftLong>-84.174615</upperLeftLong>
            <lowerRightLat>33.930329</lowerRightLat>
            <lowerRightLong>-84.16698</lowerRightLong>
        </map>
        <map>
            <ID>2</ID>
            <name>Lot – 2</name>
            <imageX>600</imageX>
            <imageY>400</imageY>
            <description>Lot 3 Description</description>
            <mapSource>lot2.swf</mapSource>
            <upperLeftLat>32.847887</upperLeftLat>
            <upperLeftLong>-96.865415</upperLeftLong>
            <lowerRightLat>32.84229</lowerRightLat>
            <lowerRightLong>-96.857924</lowerRightLong>
        </map>
    </maps>
    <screen width="500" height="350" />
</config>

Pulling the web service to get data is also easy, so I now have an application that can run on any system, with multiple maps configured. There are still a few things I need to do, but it is much better than it was a few hours ago. I also refactored the web service into testable libraries, which I briefly covered in my last blog entry.

Peace and Grace,
Greg

Why I love TDD


I just got back a project from a new vendor we are working with. I have to pass this project on to a client of ours, but first I want to make sure all of the .NET code is obfuscated. No big deal overall, as we expected this company was mid-level developers and I would have to dink it.
 
As expected, all of the code was contained in the asmx, so I decided I would start moving code to another project. I run through and figure out the lowest level item, which is to create a dictionary object for the string that will be sent to the webservice from a web app (don’t ask, it gets rather complicated. So, what do you do? Write a test. The code looks something like this:
 
[TestMethod()]
[
DeploymentItem("CompanyName.Client.dll")]
public void CreateDictionaryTest()
{
   
string stringtoBreakUp = "{string here}";
   
Dictionary<string, string> expected =
                              
TestHelper.GetExpectedDictionaryForTest();
   
Dictionary<string, string> actual =
                       
DataBaseHelper_Accessor.CreateDictionary(stringtoBreakUp );

    foreach (string key in actual.Keys)
    {
       
Assert.AreEqual(expected[key], actual[key], "Difference in value for key " + key);
    }
}

 
I run the test and it naturally fails (there is no implementation). So I implement the code to something like this (the original code was in VB, so I left it like that — just in case you wanted to know):
 

Private Shared Function CreateDictionary (ByVal str As String) _

                                          As Dictionary(Of String, String)

 

    ‘Using Generic Dictionary to make things easier (.NET 3.5)

    ‘BABELFISH: Usando el diccionario genérico para hacer cosas más fáciles (.NET 3.5)

    Dim dict As New Dictionary(Of String, String)

 

    ‘Array desde la cadena de Esns

    ‘ENGLISH: Array from the chain of Esns

    Dim arrEsn As String() = str.Split("|")

 

    ‘Add all items to a reusable dictionary

    ‘BABELFISH: Agregue todos los artículos a un diccionario reutilizable

    For i As Int32 = 0 To arrEsn.Length – 1

        ‘Descompongo clave, valor

        ‘*** Divide Hash into ESN and description

        Dim subArr As String() = arrEsn(i).Split("^")

 

        ‘Adding ESN and Description

        ‘BABELFISH: Adición de ESN y de la descripción

        dict.Add(subArr(0), subArr(1))

    Next

 

    Return dict

 End Function

 
The original routine made a rather complex SQL string and a hashtable. It was doing the work twice, so this is the first refactor. The reason for the BABELFISH comments is the developers here are offshore in South America. I am making sure they can read what I am doing, even if it is bad Spanish. Open-mouthed
 
The test now passes. This, of course is an easy test. Now, here are a list of tests I need to do to get to the end.
  1. Create a SQL String – This is just to be able to do things the way the developers did it and will be deprecated once I move to sprocs
  2. Get Vehicle List – This is a simple Get a DataSet test. And, yes, I am not using mocks at first, so this test will both altered and moved to an integration test harness
  3. Adorn the DataSet test – This one is to add the extra info sent on the original string that is ripped into a dictionary. While it is a bit crude, I prefer massaging the data up front to playing games when you bind
  4. Integration test of Getting a list of vehicles using the old signature (list string only)

In order to facilitate, I am going to move the ESN string to a TestHelper (not the actual name, but it is the purpose), so my test changes to this:

[TestMethod()]
[
DeploymentItem("CompanyName.Client.dll")]
public void CreateDictionaryTest()
{
   
string stringtoBreakUp = TestHelper.GetEsnString();

   
Dictionary<string, string> expected =
                              
TestHelper.GetExpectedDictionaryForTest();
   
Dictionary<string, string> actual =
                       
DataBaseHelper_Accessor.CreateDictionary(stringtoBreakUp );

    foreach (string key in actual.Keys)
    {
       
Assert.AreEqual(expected[key], actual[key], "Difference in value for key " + key);
    }
}

The change here is highlighted. Why move this to another class? I will need this same information over and over again. Looking at the test that gets a list from the database (the integration test), you see this:

string Esns = TestHelper.GetEsnString();
DataSet expected = TestHelper.GetDataSetOfVehiclesForTest();

 
It doesn’t get much easier to put the same data in each routine than to use a single method (code smell 101 – repeat code is BAD). By creating this helper class, I can feed each of my routines. But, it gets even sweeter. When I move the tests to an integration class, they can use the same helper. And, when I refactor to mocks, I already have a routine that helps me define what the mock should look like and deliver. Sweet!!!!
 
But, this is not even why I love TDD. When I got to my final test, which will likely remain an integration test, I went red after implementation. It delivers the exact same data set as the previous test, so it should not fail. But it did. In a non-TDD world, I would have searched for the problem for a long time, seeing the results of the issue on the UI. In TDD, I see that I have no data in the DataSet. I know the routine that grabs the data works, as it was just tested, so I can be confident the problem is in the current routine. A quick look at the routine reveals what I have not hooked  up correctly … and I do not even have to use the debugger to find it. Can life be sweeter than this.
 
If you have not been sold yet, you probably never will. But, I can’t sell all of the people all of the time.
 
Peace and Grace,
Greg

Consuming XML in ASP.NET 2.0+


The question came into the Microsoft Expression Web forum. I would have answered it there, but two things happened:

  1. Microsoft is dinking with the site tonight and it is broken as soon as you sign in with passport.
  2. I felt this was better here

Let’s ignore #1 for now, as it is out of my control and focus on #2. While this post was in Expression, it is a problem that everyone who attempts to consume XML will run into. Here is the question, so you have the context:

I have an Access 2007 Database and I want to export data in an XML format for inclusion into my web site.  While Access will export the file, it is in a format EW does not accept when I try to create a Grid View.

<?xml version="1.0" encoding="UTF-8" ?>
– <dataroot xmlns:od="urn:schemas-microsoft-com:officedata" generated="2008-06-18T11:20:50">
– <WebMachines>
<MachineID>6407</MachineID>
<TypeMachine>AUTO SCREW MACHINES, SWISS, CNC-MILL & SUB SPDL</TypeMachine>
<Year>2000</Year>
<Manufacturer>Nomura</Manufacturer>
<Model>NN-13TB</Model>
<Control>Mitsubishi Meldas 520L</Control>
<Condition>Very Good</Condition>
<List>2000 Nomura NN-13TB Mitsubishi Meldas 520L</List>
<Code>A8175MS</Code>
<Featured>0</Featured>
</WebMachines>

Now the XML data that is in the Sample file Members.xml works fine.  I guess I am confused why EW will not accept an XML file from an up-to-date version on Access 2007???

<members>
<member isactive="true" groupcolor="#FFCC3333" name="Tom Jackson" datejoined="10/06/2006" />
<member isactive="false" groupcolor="#FFA4AB28" name="Stacey Footheart" datejoined="11/10/2006" />
<member isactive="true" groupcolor="#FFA6D877" name="Jack Herdin" datejoined="6/10/2006" />
<member isactive="true" groupcolor="#FF138C48" name="Kim Getruds" datejoined="4/15/2006" />
<member isactive="false" groupcolor="#FF5FADB9" name="Larry Nusom" datejoined="7/12/2006" />
<member isactive="true" groupcolor="#FF3B1076" name="Gary Heart" datejoined="9/21/2006" />
</members>

Is there anyway to export data from a Access 2007 database that EW will accept cleanly?  I have tried every possible way to export an XML file format that EW will accept. I thoughts these programs were suppose to work with each other cleanly?

I will show two ways to skin this cat. Before doing that, we need to clean up the XML a bit. First, all ampersands need to be convered to &amp;. The same is true if there is any other reserved word. The second is to close out the </dataroot>. And the third is to get rid of the hyphens (I assume it was copied out of Internet Exploder.

<?xml version="1.0" encoding="UTF-8" ?>
<dataroot xmlns:od="urn:schemas-microsoft-com:officedata" generated="2008-06-18T11:20:50">
<WebMachines>
<MachineID>6407</MachineID>
<TypeMachine>AUTO SCREW MACHINES, SWISS, CNC-MILL &amp; SUB SPDL</TypeMachine>
<Year>2000</Year>
<Manufacturer>Nomura</Manufacturer>
<Model>NN-13TB</Model>
<Control>Mitsubishi Meldas 520L</Control>
<Condition>Very Good</Condition>
<List>2000 Nomura NN-13TB Mitsubishi Meldas 520L</List>
<Code>A8175MS</Code>
<Featured>0</Featured>
</WebMachines>
</dataroot>

<asp:xml>

Our first method of solving this is the ASP.NET XML control. Since the person was attempting to do this in Expression, let’s start there.

  1. Add the XML file to the website (App_Data is the best location, IMO)
  2. Drag the XML node <WebMachines> onto the page
  3. Preview

If you have a single WebMachines tag, you end up with a vertical display of the column nodes. If you have more than one, you end up with a grid. Fairly simple stuff. The XSL does all of the dirty work and you can edit the XSL file created or use the presets.

GridView and XmlDataSource

This is a bit more involved, but still fairly simple. As the XML is not using attributes (the default for auto generated columns), you will have to tell how to render the GridView.

First, drag an XmlDataSource control on the page. Browse for the xml file and select it for the first text box. Do not fill the XSLT textbox (2nd down), but do set the XPATH to /dataroot/WebMachines.

Then, drag a GridView on the page and set it to the XmlDataSource. You then will have to add templated columns and drag a label into each one. Here is the first column (MachineID):

<asp:TemplateField HeaderText="ID">
  <ItemTemplate>
    <asp:Label runat="server" ID="lblMachineID" Text='<%#XPath("MachineID")%>’/>
</ItemTemplate>
</asp:TemplateField>

The XPATH is the key here when you are not using attributes. The complete source of the page is as follows, although I am only showing a few of the "columns" in the XML file.

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

<%@ Page Language="C#" %>

<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
    <title>Untitled 1</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:xmldatasource id="XmlDataSource1" runat="server" datafile="Test.xml" xpath="/dataroot/WebMachines">
    </asp:xmldatasource>
        <br />
        <asp:gridview id="GridView1" runat="server" datasourceid="XmlDataSource1" autogeneratecolumns="false">
          <Columns>
         <asp:TemplateField HeaderText="ID">
           <ItemTemplate>
             <asp:Label runat="server" ID="lblMachineID" Text='<%#XPath("MachineID")%>’/>
         </ItemTemplate>
         </asp:TemplateField>         
         <asp:TemplateField HeaderText="Machine ID">
           <ItemTemplate>
             <asp:Label runat="server" ID="lblTypeMachine" Text='<%#XPath("TypeMachine")%>’/>
         </ItemTemplate>
         </asp:TemplateField>
                   <asp:TemplateField HeaderText="Year">
           <ItemTemplate>
             <asp:Label runat="server" ID="lblYear" Text='<%#XPath("Year")%>’/>
         </ItemTemplate>
         </asp:TemplateField>
                 <asp:TemplateField HeaderText="Manufacturer">
           <ItemTemplate>
             <asp:Label runat="server" ID="lblManufacturer" Text='<%#XPath("Manufacturer")%>’/>
         </ItemTemplate>
         </asp:TemplateField>
                           <asp:TemplateField HeaderText="Model">
           <ItemTemplate>
             <asp:Label runat="server" ID="lblModel" Text='<%#XPath("Model")%>’/>
         </ItemTemplate>
         </asp:TemplateField>
        </Columns>    
    </asp:gridview>
    </form>
</body>
</html>

Wasn’t that quite easy? Of course, the tools do not do all of this for you, which may be "problematic" for some, but the syntax is still completely declarative.

Peace and Grace,
Greg

ASP.NET MVC Preview 3: PLaying with ViewPage


Note: This entry may ramble a bit, as it is being written as I experiment.
 
I have now been in the waters long enough to be baptized and wanted to play around a bit while I blog. This first post is based on an issue I noticed in Preview 2 with the MVC Membership Starter Kit (blogged in my last entry) and how I played around with it.
 
Suppose you wish to include some JavaScript in your page and feed it from view data. Let’s do something really simple that is potentially error prone. We are going to create a simple form with a button and we are going to use ViewData. Simple enough, eh? To make this simple, let’s just whack the default set up. After all this is just a test, right? In this, we will create a JavaScript that displays a message.
 
So, create a new MVC project from the template. Then, open the controller and put the following in the index() action result method:
 
public ActionResult Index()
{
    ViewData[
"Title"] = "Home Page";
    ViewData[
"Message"] = "Welcome to ASP.NET MVC!";
   
//Add this line
    ViewData["AlertMessage"] = "This is a message in a popup";

    return View();
}

 
Now, move to the view and place the JavaScript bits in the View.
 
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%= Html.Encode(ViewData["Message"]) %></h2>
    <p>
        To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc&quot; title="ASP.NET MVC Website">http://asp.net/mvc</a>.
   
</p>
    <script>
    /* <![CDATA[ */
    alert(‘<%= ViewData["AlertMessage"] %>’);
   
/* ]]> */
    </script>

</
asp:Content>
 
The portion highlighted is all that I added to the mix. If we run the page now, we have a popup with an alert message. The next step is to add a button to the form, so we can pretend this is a form. So, I add the following:
 
    <% using(Html.Form("Home", "SimpleSubmit"))
       {
%>
      
       <%
=Html.SubmitButton("submit","Submit", null) %>
      
    <% } %>
 
While this is not a test, let’s run a red … green … refactor exercise anyway, even if it is backwards (should have tested the controller first). I open the page again and there is a button. Clicking the button produces an error:
 

Server Error in ‘/’ Application.


The resource cannot be found.

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable.  Please review the following URL and make sure that it is spelled correctly.

Requested URL: /Home/SimpleSubmit


Version Information: Microsoft .NET Framework Version:2.0.50727.1434; ASP.NET Version:2.0.50727.1434

 
This is just what I expected! Smile Now, we will implement this in the controller as a method called SimpleSubmit() – yes, the name sucks, but this is an inane example to illustrate a point.
 
        public ActionResult SimpleSubmit()
        {
            ViewData[
"Title"] = "Home Page Submitted";
            ViewData[
"Message"] = "You just clicked my button!";

            return View("Index");
        }

 
Run the app again and click the submit button and what happens? Empty message in the popup. This is a bit nicer than preview 2, which would error out.
 
Oh, since this is an empty popup, I am going to assume we only want a popup when there is a message. One way to do this is to check if the ViewData contains this key.
 
    <% if(ViewData.ContainsKey("AlertMessage"))
       {
%>
   
<script>
    /* <![CDATA[ */
        alert(‘<%= ViewData["AlertMessage"] %>’);
   
/* ]]> */
    </script>
    <% } %>

This at least keeps things a bit sane, but it is not completely to my liking. How about if I control the class that feeds the page? First, we code a simple class:

public class TestClass
{
   
public string Title { get; set; }
   
public string Message { get; set; }
   
public string AlertMessage { get; set; }

    public TestClass(string title, string message, string alertMessage)
    {
        Title = title;
        Message = message;
        AlertMessage = alertMessage;
    }
}

 
Now, this does not buy me much, but it does allow me to simplify my Index() method, which makes it a decent enough refactor. The Index method now looks like this:
 
    public ActionResult Test()
    {
       
TestClass test = new TestClass("Home Page"
            , "Welcome to ASP.NET MVC!"
            , "You just clicked my button");
       
return View("Test", test);
    }
 
To make this actually work, I have one other small step. I have to change the Index declaration to take the TestClass.
 
    public partial class Index : ViewPage<TestClass>
    {
    }
 
There is another syntax you can use here if you want to avoid having an empty code behind file, which is detailed on Troy Goode’s blog. The basic syntax is:
 
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage`1[ [MyCompany.MyProject.TestClass,MyCompany.MyProject] ]" %>
 
In this, you are stating the name of the class followed by the name of the assembly it is contained in. As I mentioned, Troy has further details in this post.
 
Now, the first thought may be "you need to change the code in the page", but that is not correct. When you make a simple class like this, it can pull directly from the elements using the syntax we are already using. To prove this, let’s change the page, but avoid the Master Page, which contains the following line:
 
<title><%= Html.Encode(ViewData["Title"]) %></title>
 
The page will be changed to the following:
 
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
AutoEventWireup="true" CodeBehind="Test.aspx.cs" Inherits="TestMVC.Views.Home.Test" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%= ViewData.Model.Message %></h2>
    <p>
        To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc&quot; title="ASP.NET MVC Website">http://asp.net/mvc</a>.
   
</p>
    <% using(Html.Form("Home", "SecondSimpleSubmit"))
       {
%>
      
       <%
=Html.SubmitButton("submit","Submit", null) %>
      
    <% }
%>
    <%
if(ViewData.Model.AlertMessage != String.Empty)
       {
%>
   
<script>
    /* <![CDATA[ */
        alert(‘<%= ViewData.Model.AlertMessage %>’);
   
/* ]]> */
    </script>
    <% } %>
</asp:Content>
 
Run the page and it works fine, so we can use one of two syntaxes when we are using ViewPage<T> with a class with simple properties:
 
alert(‘<%= ViewData["AlertMessage"] %>’);
 
or
 
alert(‘<%= ViewData.Model.AlertMessage %>’);
 
NOTE: If you are using a build prior to Preview 3 for some reason, you will have to use ViewData.Property instead of ViewData.Model.Property.
 
Now, this really does not provide me much at this point in time, but it does give me the potential to simplify rather large JavaScript sections (something more than an alert, by adding a public property for AlertJavaScriptBlock (I will work on the names later), which allows me to do something like:
 
    <% if(!ViewData.Model.IsPostBack){ %>
       <%
=ViewData.Model.AlertJavaScriptBlock %>
    <% } %>
 
There has to be a way to write this even more tersely, but I will have to figure out what <%= %> corresponds to in code (something similar to Response.Write?). If you know, just ping me, as I would love to keep the syntax as tight as possible. Regardless, "injecting" the entire JavaScript block when needed, I avoid a lot of code in the view. This is important to me as I already have components outputting a large amount of client side JavaScript (a MapQuest API component primarily).
 
One problem solved. I now have to go to themes and dink a bit further with Membership. I am sure I will blog more about these adventures.
 
Peace and Grace,
Greg

Debugging versus Testing (MVC, Web 2.0)


I have been playing with ASP.NET MVC lately and I hvae noticed one interesting artifact of the methodology, at least for time being. WIth ASP.NET, you have a good debugging experience. With MVC, you have a good testing experience.
 
This is not a blanket statement, of course, as debugging is quite easy in MVC, as long as you are in the controller. But, consider the following scenario (yes, I will give the solution to this problem, as well).
 
You fire up the MVC Membership starter kit. You hook it up to SQL Server (blog entry here). You are now able to log in. Go to change password and you end up with a NullReferenceException on this line (highlighted)
 

<script type="text/javascript">
/* <![CDATA[ */


  function starterKit_mvc_membership_validateChangePassword()
  {


    var pwd_minChars = <% =(int)ViewData["MinimumPasswordLength"] %>;

Nothing really stellar here. This is just a bug in the software. Normally, when you find a bug like this, you would go to the call stack and find out what the calling member was sending in. You would also get a good spot to set your breakpoints. This is not as straightforward, however, in MVC, because the call stack is pretty much non-existent once you are filling the view. You cannot step back into the controller and find the reason for the error.
 
In the future, Microsoft may have a solution for this. For now, you have to work with the new way of thinking and do a bit of investigation. Since this is the PasswordChange view in the FormsAuthentication folder, I am looking for hte FormsAuthenticationController. The code is not here, however, because it is a derived class.
 

public class FormsAuthenticationController
    : StarterKits.Mvc.Membership.Controllers.
BaseFormsAuthenticationController

 
So I set my breakpoints in the BaseFormsAuthenticationController instead. Line 709 yields the answer (or rather line 709 and scouring the entire PasswordChange() routine yields the answer). The only thing in ViewData is a Boolean:

// success!
ViewData["Success"] = true
;
return RenderView( "PasswordChange" );

The code ran perfectly and my password has changed, but I am still treated with an error trying to fill the JavaScript on the form. NOTE: Will hit possible solutions later.
 
The problem here is not Troy’s code, it is the experience. We all end up with bugs in our code as we write applications. In fact, we expect bugs as we code, and that is why test driven development is so important. It helps us find the bugs quickly. The problem here is a disconnect between the UI bits and the backend. And, it is not unique to MVC. A few weeks ago, I blogged about clashes between ASP.NET AJAX and the MapQuest tiled map API. I have also had issues with over engineered CSS clashing with CSS packed with controls.
 
The debugging experience on the client is very rudimentary at the present time. And, there is a huge gulf between backside debugging and client side debugging. In general, I find myself using Firefox a lot when I am working with server code that outputs client side code. Currently, Firefox has the best client side debugging tools, which leaves a huge opportunity for Microsoft, as these tools cannot adequately link the two disparate parts of the Web 2.0 application in a single debugging environment. To be fair to Microsoft, they have tried with Visual Studio and Internet Explorer. If you flip off the Disable Script Debugging checkbox, you can end up with some JavaScript debugging goodness. But, you are still debugging one set of code in isolation, even if you are using the same tool.
 
I wish I had an answer on how to solve the problem. While we want a debugger that allows us to go through the entire chain of events, it gets rather complex to link views to controllers in the debugger. It is even more difficult to follow code from server side to the client side. I am optimistic that it is not impossible, but wonder if it is possible without further bloating the development environment to the point that the experience is degraded.
 
Silverlight overcomes this problem, to a large extent, as the code is all .NET. There are still some gotchas, but you have a clean separation of client and server in Silverlight … at least if you develop the server end like a service. Software as a Service – what a unique concept! Wink MVC has the ability to overcome this problem, as well, but is a bit more complex as views are not running the code in a traditional sense. The separation is also NOT clean, at least not in the plethora of examples on the web. The same is true with web 2.0 technologies, although they are maturing a bit and people are getting the SOA/SAAS idea.
 
I am sold on the TDD aspects of MVC. As I have stated before, I am not sold that it is the only way, but MVC really does force separation of concerns. I am not sold on the current view model, especially with views peppered with ASP like code. I am sure that will change over time once the Framework understands all of the fundamental controls.
 
Now, back to the problem at hand, since somebody will ask if I don’t spout off. My first thought is one of two solutions:
  1. Create the JavaScript completely server side and inject it
  2. Flip to a different view for confirmation

#2 will be easier, but I need to solve #1 regardless to use the tiled maps (MapQuest currently) in MVC. An injection type model is easier to debug, as all of the code is server side until it is placed on the page. It does lead to having to test the UI to get the bits down and completely debug the solution, but a view of tags and code leads to the same issue. At least with an injection of client side code model, I can debug the JavaScript separately from the code that builds it. Smile

Peace and Grace,
Greg

Setting up the ASP.NET MVC Membership Starter Kit with SQL Server


I just got a chance to download and begin looking at the new ASP.NET MVC Membership bits from Troy Goode (www.squaredroot.com). The project is a starter kit that puts the standard ASPNETDB membership bits (the ones you can create with aspnet_regsql) in the MVC Framework.
 
When I first downloaded, I had a hard time getting things to work using his standard ASPNETDB instance when it was hooked up to SQL Server (not SQL Express). At first, I thought I was having a problem connecting to the database, but I created a little page called test.aspx and did the following:
 

namespace MvcMembership
{
   
public partial class test : System.Web.UI.Page
    {
       
protected void Page_Load(object sender, EventArgs e)
        {
            TryDatabaseConnection();
            TryMembership();
        }

        private void TryMembership()
        {
           
try
            {
                Response.Write(
string.Format("App name: {0}<br/>",Membership.Provider.ApplicationName));

                MembershipUser user = Membership.GetUser();
                Response.Write(
"Success on Membership<br/>");
            }
           
catch (Exception ex)
            {
                Response.Write(
"Failed on Membership<br/>");
                Response.Write(
string.Format("Error Type: {0}<br/>", ex.GetType().ToString()));
                Response.Write(
string.Format("Message: {0}<br/>", ex.Message));
                Response.Write(
string.Format("Source: {0}<br/>", ex.Source));
            }
        }

        private void TryDatabaseConnection()
        {
           
string connString = ConfigurationManager.ConnectionStrings["ASPNETDBConnectionString"].ToString();
           
SqlConnection connection = new SqlConnection(connString);

            try
            {
                connection.Open();
                Response.Write(
"Success on Database Connection<br/>");
            }
           
catch (Exception ex)
            {
                Response.Write(
"Failed on Database Connection<br/>");
            }
           
finally
            {
                connection.Dispose();
            }
        }
    }
}

I was able to connect to the database, but not the Membership bits. Rather than go through all of the steps, I will tell you what you need to do get this running quickly.

First, create your ASPNET Membership database. The easiest way to do this:

  1. Open a VIsual Studio 2008 Comand Prompt
  2. Type aspnet_regsql and hit enter
  3. Click next
  4. Keep the default "Configure SQL Server for application services" and click next
  5. Choose the database and click next, next and then finish

If you like to be a maverick, the install scripts are also located at %windir%/Microsoft .Net/Framework/v2.0.50727. It does not really matter how you create the database.

You now need to go to the sample MVC Membership web application and edit the web.config. By default, it is implicit and only contains the following Membership bits.

    <connectionStrings>
        <
add name="ASPNETDBConnectionString"
        
connectionString="Data Source=.SQLEXPRESS;AttachDbFilename=|DataDirectory|ASPNETDB.MDF;Integrated Security=True;User Instance=True"
        
providerName="System.Data.SqlClient" />
    </
connectionStrings>


<roleManager enabled="true" />

You need to fill this in. First, replace the connection string with the connection string to your database:

    <connectionStrings>
        <
add name="ASPNETDBConnectionString"
        
connectionString="Server=(local);Database=ASPNETDB;UID={Membership User};PWD={user password};"
        
providerName="System.Data.SqlClient" />
    </
connectionStrings>

You then need to fill in the implied bits with real bits. This means the <roleManager enabled="true" /> will become something like:

<membership userIsOnlineTimeWindow="20" defaultProvider="AspNetSqlProvider">
  <
providers>
    <
add connectionStringName="ASPNETDBConnectionString"
        
minRequiredPasswordLength="8"
         minRequiredNonalphanumericCharacters="1"
        
requiresQuestionAndAnswer="true"
         applicationName="/"
        
passwordFormat="Encrypted"
        
passwordAttemptWindow="10"
         enablePasswordReset="true"
        
enablePasswordRetrieval="true"
        
name="AspNetSqlProvider"
        type="System.Web.Security.SqlMembershipProvider" />
  </
providers>
</
membership>
<
roleManager defaultProvider="RoleManagerProvider"
             enabled="true"
             cacheRolesInCookie="true"
             cookieName=".ASPROLES"
             cookieTimeout="30"
             cookiePath="/"
             cookieRequireSSL="false"
             cookieSlidingExpiration="true"
             cookieProtection="All">
  <
providers>
    <
add name="RoleManagerProvider"
         type="System.Web.Security.SqlRoleProvider"
         connectionStringName=" ASPNETDBConnectionString "
         applicationName="/" />
  </
providers>
</
roleManager>

Notice the highlighted section. It is important. The normal value here is hashed, but I want to be able to reverse engineer the passwords for admin purposes (a feature I will have to add to the MVC bits). To use encrypted, I will have to work with the machineKey section of the config. This looks like this:

    <machineKey validationKey="{Validation Key Here}"
        decryptionKey="{Decryption Key Here}"
        validation="3DES"/>

If you need to gen keys, you can use Ben Strackany’s key generator. You will need a Code Project account (free) to download the project:
http://www.codeproject.com/KB/aspnet/machineKey.aspx

If you do not have an account on Code Project, and don’t want one, Peter Bromberg has created a sample page that will create these keys, as long as you want to use SHA1 for validation (yes, you can alter this):
http://www.eggheadcafe.com/articles/20030514.asp

The final step is seeding the database. The easiest way is to open the web configuration tool. When it connects to the database, it will create a record in aspnet_applications for the / application. You will have to go through the wizards to create your administrator accounts.

I have also included a script for you to run, if you are not big on using the web configuration tool. If you use the script, you will have to set up the following machineKey section in your web.config, as the passwords are encrypted using these settings (NOTE the validation key is on two lines as spaces truncates things — you must fix that in your web.config when you copy and paste this):

<machineKey
validationKey=
"2AB9BB5084E7E8E34ECAA89E37B542E50D0C7E486D606804021812400A6E2EEDAF80F5E4
798B44EC71B0403F91D33B3208C170A34453B2A51A9EDA27839C6552
"
decryptionKey="B2F58C16DEBB63B7CE25D5CD239CCDB0D71E160FE7FD65BC6CD1D0C98BAD29FA"
validation="SHA1" decryption="AES" />

Here is the script:

/***********************************************
*     ASP.NET MVC Application Seeder
*   ——————————————–
*     User Name:  Administrator
*     Password:   password!1
*
*     Security Question:
*     What is the velocity of an unladen sparrow?
*
*     Security Question Answer:
*     European or African?
***********************************************/

— Create the application
insert into aspnet_applications (ApplicationName
                               
, LoweredApplicationName
                               
, ApplicationId
                               
, [Description])
values (‘/’
        , ‘/’
        , ‘3A168FD5-07E8-49FB-9C95-F8D15A9DA6E7’
        , ‘Default application for the sample ASP.NET MVC Applicatio’)
GO

— Create the administrator role
insert into aspnet_roles (ApplicationId
                                         
, RoleId
                                         
, RoleName
                                         
, LoweredRoleName
                                         
, [Description])
values (‘3A168FD5-07E8-49FB-9C95-F8D15A9DA6E7’
            , ‘072EA006-37E8-42DE-8FCA-BE790BF61BFA’
            , ‘Administrator’
            , ‘administrator’
            , ‘Administrator role for the sample ASP.NET MVC Applicatio’)
GO

— Create the Administrator user
insert into aspnet_users (ApplicationId
                                    , UserId
                                    , UserName
                                    , LoweredUserName
                                    , IsAnonymous
                                    , LastActivityDate)
values (‘3A168FD5-07E8-49FB-9C95-F8D15A9DA6E7’
            , ‘DE313B04-D60B-4E6B-B790-8F56FDB96C17’
            , ‘Administrator’
            , ‘administrator’
            , 0
            , GetUtcDate())
GO

— Create the user membership bits
insert into aspnet_membership(ApplicationId
                              , UserId
                              , [Password]
                              , PasswordFormat
                              , PasswordSalt
                              , MobilePIN
                              , Email
                              , LoweredEmail
                              , PasswordQuestion
                              , PasswordAnswer
                              , IsApproved
                              , IsLockedOut
                              , CreateDate
                              , LastLoginDate
                              , LastPasswordChangedDate
                              , LastLockoutDate
                              , FailedPasswordAttemptCount
                              , FailedPasswordAttemptWindowStart
                              , FailedPasswordAnswerAttemptCount
                              , FailedPasswordAnswerAttemptWindowStart
                              , Comment)
VALUES (‘3A168FD5-07E8-49FB-9C95-F8D15A9DA6E7’
            , ‘DE313B04-D60B-4E6B-B790-8F56FDB96C17’
   
, ‘e4esufQBWoB7uWAAaCMH5TgeqPmozkIp+YAYDrq9NInu+1ovT+GWfuDjLZPMMAiT’
   
, 2, ‘EzaAKgyIzgckUbbEzmW0lQ==’
   
, NULL
    ,
‘admin@company.com’
   
, ‘admin@company.com’
   
, ‘What is the velocity of an unladen sparrow?’
   
, ‘e4esufQBWoB7uWAAaCMH5W3g/LF9xTjDpDr0yA88cwd53dNpxV8JGkzVZPQV0a+cxrJ1v+osHSg7RLqTRU4Vaw==’
   
, 1
    , 0
    , GetUtcDate()
    ,
CAST(0x00009AB8015CEC03 AS DateTime)
    ,
CAST(0x00009AB8015CEBD4 AS DateTime)
    ,
CAST(0xFFFF2FB300000000 AS DateTime)
    ,
0
    , CAST(0xFFFF2FB300000000 AS DateTime)
    ,
0
    , CAST(0xFFFF2FB300000000 AS DateTime)
    ,
‘Administrator for the sample ASP.NET MVC Application’)
GO

— Link the Administrator user to the Administrator role
insert into aspnet_usersinroles (UserId
                                                , RoleId)
values (‘DE313B04-D60B-4E6B-B790-8F56FDB96C17’
            , ‘072EA006-37E8-42DE-8FCA-BE790BF61BFA’)
GO

You should now be able to log in with the admin credentials (listed in the flower box at the top of the SQL script).

Beyond learning how to hook the ASP.NET MVC site into SQL Server Standard, Dev or Enterprise, you have learned how to fix membership bits. Just follow the steps in this blog post to fix an errant membership database. Here is the order of troubleshooting:

  1. Can I connect to the database?
    If no, you have to fix the connection string.
  2. Can I connect to membership? Things to check if not
    a) Do I have web.config set up correctly for membership?
    b) Do I have web.config set up correctly for roles? (if you are using roles)
    c) Do I have an application node in aspnet_membership?
    d) Am I using the correct machine keys?

Hope this helps!

Peace and Grace,
Greg