EZWeb v1.2 now released!!! Go download.

I’ve finally released my next version of EZWeb.  You can download it from the GotDotNet workspace.  EZWeb is a website management system.  Drop it into IIS, set the NTFS permissions to the ASPNET (or NETWORK SERVICE) account, and you can immediately begin to grow a website, or create an account for your mother and let her do it (complete with image and file upload).


EZWeb is the simplest website management system.  No database is required at all.  All changes can be done from the browser.   EZWeb is not a portal framework, and doesn’t compete with DNN.  EZWeb allows websites to be set up and grown “eazily”.  You will start with one page, and you can grow the website, or you can create many users and delegate parts of the website they can grow.


This is a perfect system for user group websites.  Get information up quickly, and post ppt slides after events.  Create an account for each UG member and let them have a personal section.


EZWeb is free for non-profit use.  I encourage everyone to download it and give it a whirl.  I started this project in 2003 when I was deployed to Iraq.  It’s come a long way since then, and I already have a long list of improvements, so please give me your feedback and feature-requests.


Because “plugins” are just ASP.NET controls, any control can be loaded and used with EZWeb.  I’ll be posting answers to questions as they come.

cursor: hand; and cursor: pointer explanation – level 200

Even though FireFox is now losing ground to Internet Explorer, web developers must still ensure websites and web applications look good and function well in all the browsers potential customers may be using.  It is irresponsible to only test a web application in one browser when users may use the application for multiple browsers.


There are many special things one must do to ensure browser compatibility.  Using CSS is one of them, but even with a well-defined style sheet, browser differences can cause headaches.


In order to ensure that the mouse pointer is a hand over any given element, use:


*.myStyle
{
   cursor: hand;
   cursor: pointer;
}


This will be effective in all the major browsers.  cursor: hand; works in IE, and without testing with another browser, one would not find this visual bug.  FireFox, for instance will only recognize cursor: pointer;  IE 6 will recognize cursor: pointer, but IE 5 won’t.  Using both declarations will ensure the proper look in all the major browsers.


References:
http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/properties/cursor.asp
http://www.quirksmode.org/css/cursor.html

SOA Pattern: Document Processor – level 200

At the Austin Architect Council, Ron Jacobs spoke about an SOA pattern that hit home:  The Document Processor.  Here is how he described it:


Think back to before computers ran everything.  Units of work (like a work order) were represented by a business form.  These documents normally had several carbon copies.  After the form was completed, copies were sent to different departments.  If it was a work order, perhaps the maintenance department received the document.  Receipt of the document kicked off the task, and the work got done.  Ron says that this is how service interfaces should operate.  The schema (message) should consist of the entire business document.  In this way, the service’s implementation is hidden (such as what database is used).   With the business document as the message, the service can be easy to consume from any platform, and one call can represent a single unit of work. 


In this way, a communication failure doesn’t leave the service in an incomplete state.  Does this mean that you can’t do transacted services????  YES!!!  If you need transactions, then stop looking at SOA to solve that problem. 


The benefit of the Document Processor pattern is that client developer only have to think about sending a document.

What is SOA according to Ron Jacobs – level 300

A few weeks ago, Ron Jacobs stopped by the Austin Microsoft Technology Center to talk about the CAB and SOA.  Ron gave the best explaination of SOA that I’ve heard so far, and none of it was at any extreme.  He covered the four “requirements” of SOA:



  • Boundaries are explicit

  • Services are autonomous.

  • Schema and contract are shared, not class

  • Compatibility is determined by policy.

My favorite line from the talk was that SOA simply seeks to make integration a forethought when building an application instead of an afterthought like it is today (many companies have existing applications that they are now trying to integrate or share).


Boundaries:
Some boundaries are like International boundaries.  You have to go slow.  You may be stopped and searched.  When you need to cross this boundary, you plan for it.  Other boundaries are like interstate boundaries.  You control both sides, and you can typically fly across the border at 70 mph.  The relationship to SOA is that service boundaries are explicit like International boundaries.  You need to slow down and plan for crossing.  Component boundaries are like interstate boundaries, and you can fly across those using any fast communication mean you want because you control both sides.


Autonomous:
A service is sovereign over its space.  Service can be composed of other services.  Autonomy is not black and white.  There is a specrum, and you want services to be more toward the autonomous side.  If a service delegates to a dependency, the failure of that dependency should not automatically halt the service.


Schema and Contract:
The schema is the format of the message that will be passed.  The contract is the action that the service can be trusted to commit with the message.  This is tightly coupled with policy.


Policy determines compatibility:
Many services today use MSMQ, or MQ Series products.  This is not to say that services have to be asyncronous, but to say that SOA isn’t just about web services.  If the policy states that the schema must be compatible with a bunch of systems, then the schema will have to be a text schema, and Xml is great for that.  If the policy states that only a few clients are supported, then a faster, more efficient schema can be used, perhaps binary, as long as the few clients can understand the message.  Services can use any communication mechanism, not just SOAP, to communicate, but this decision is set by the Policy in place.


Ron also went over an anti pattern, the CRUDy interface.  This is a service interface that behaves much like an OO component.  This makes for a chatty interface of creates, reads, updates and deletes.  This puts the clients in the wrong frame of mind, and it encourages an RPC style of development.  This requires clients to know too much about the internal implementation of the OO system behind the service interface.


Examples of this are



  • Enumerated interfaces (a MoveNext endpoing).

  • Abstract types (xs:any).  This weakens the interface.  Keep to explicit types.

  • Leaving data in an inconsistent state (if the client failed to make another call, would the service be in a “dirty” state).

  • Operations that require multiple messages are dangerous because the service sacrifices some autonomy to the client.

Another anti pattern: loosey-goosey (or exteeennnsible).
This happens when a contract may need to be used for a long time.  If a contract is extensible, then it is vague.  Services that have a “QueryDatabase” command are a good example.  A client should be able to ask “What can I send”, and the contract should explicitly answer the question.  The client developer shouldn’t have to experiment with the service to find acceptable input. 


Each endpoint should do distinct things.  A loosey-goosey service has to be learned by experimentation.  People then tend to depend on implicity behavior instead of the explicit contract.

How to understand System.NullReferenceException, Object reference not set to an instance of an object – level 200

You probably get this error message more than others, and the cause is that a variable is used in code, but that variable doesn’t contain a reference to any object in memory.  If you try to call .ToString() on an object, and your variable is null, you’ll get this exception.  Sometimes it can be hard to figure out what’s going on, but if you look at your stack trace, you can find out what method this Exception came from.  Then, debug through that method and find the offending variable. 


Likely causes are methods that take arguments but don’t validate them.  If you accept an object as an argument, and you need the “Name” property from the object, you’ll get this exception if “null” was passed in instead of a valid object instance.  If would be wise to add argument validation to the beginning of every method that may have callers you don’t completely trust.  Err on the side of caution.  Code defensively.  Input is evil.  If your arguments pass validation (ensuring they aren’t null is a common validation), you’ll likely minimize the frequency of this nasty exception.


You likely won’t get much love from Google when searching on this exception because the root cause is different in every scenario.  There’s no “magic” code snippet that will make this puppy go away.  Understand the code and properly validate, and you’ll sleep better, and your code will be more robust.

Ron Jacobs at the Austin Architect Council on Composite UI Application Block – level 200

On Monday, Microsoft held an Architect Council at the MTC. Ron Jacobs from the patterns and practices group was in town and spoke about the upcoming Composite UI Application Block (or CAB) as well as his take on SOA. Ron runs the patterns and practices group at Microsoft and has a series of related podcasts.


Ron related that he doesn’t like the DataSet because it is unstructured data. I have to agree with him. I recently ripped a DataSet out of EZWeb because it was annoying me. I replaced it with a data transfer object specifically suited to the purpose.


The Composite UI Application Block is written for .Net 2.0 and will ship along with the rest of Whidbey. It’s goal is to make smart client apps easier to develop. Ron recognizes that more and more smart client applications will have mutliple panes and not just a series of single forms. The CAB is largely based on lessons learned from when Microsoft created the Integrated Dell Desktop for Dell, Inc. The IDD is a smart client app framework that loads modules and hosts them. Modules are the individual application segments, and the smart client framework allows them to work together. It’s the application shell.


The CAB introduces a new dependency injection framework from Microsoft based on attributes. Personally, it’ll have to be really good if they expect people to switch from Spring.


Modules in applications using the CAB can publish events and subscribe to events. This communication is managed by the CAB which is highly instrumented to allow for sophisticated debugging. The CAB offers things called application services which are components that are meant to be shared by the entire application. All code runs in the same AppDomain, and each pane, dubbed a “Smart Part”. This is a takeaway from “Web Part”.


Hands-on labs for the CAB will be available soon. To download the CAB, go to http://practices.gotdotnet.com/workspace.aspx?id=22f72167-af95-44ce-a6ca-f2eafbf2653c


Check out http://msdn.demoservers.com/ for all kinds of hands-on demos of Microsoft products.

A symptom of bad code – level 100

Take the following code:


using System;

using System.Collections.Generic;
using System.Text;


 


public class ClientCode


{


    public void CallAnOperation()


    {


        string fileName = string.Empty;


        int lengthOfFile = 0;


 


        Getter get = new Getter();


        get.GetFile(ref fileName, ref lengthOfFile);


 


        Doer doGuy = new Doer();


        int retValue = doGuy.DoSomething(fileName, lengthOfFile);


 


        if(retValue != 23) //throw an exception, etc.


    }


}


 


public class Getter


{


    public void GetFile(ref string name, ref int length)


    {


        //Do some work to get file, and then. . .


        name = “myFileName.txt”;


        length = 98;


    }


}


 


public class Doer


{


    public int DoSomething(string fileName, int fileLength)


    {


        //Do something with this information. . .


        //We’ll pretend the the operation succeeded and return 23;


        return 23;


        //If the operation had failed, we would have returned 67.


    }


}


There are several issues with the above code.  Kudos to you if you already know what’s going on. 


First, my CallAnOperation() method needs values for fileName, and lengthOfFile.  He passes references to these two into a class that initializes them to correct values.  This is the first mistake.  Now the CallAnOperation() method has to have intimate knowledge of the inner behavior of the GetFile method.  This is bad and leads to tightly-coupled code that doesn’t make sense.  Instead, the GetFile method should return an object that contains the needed information. 


The second issue is with the DoSomething method.  This method has custom return codes to signal if things are good or bad.  This requires the user code to know that “23” is a good number, and “67” is a bad number.  Again, this is forcing knowledge onto the client.  The CallAnOperation() method shouldn’t have to know how a component functions.  The method names should be descriptive enough, and the return value should be quickly understandable.  At most, returning true or false may be acceptable, but a more preferrable approach is:  if something unacceptable happened, throw an exception.  If validation is in the method and is the cause for a return value instead of an exception, consider refactoring the validation into a separate method.

How to get FitNesse to switch to .Net mode – level 300

FitNesse is an acceptance test framework that supports Java and .Net.  When you download it, it will be in Java mode, and all the sample test pages will run Java tests.  It may not be completely clear how to run a new test page against a .Net assembly instead of a Java package.  When you create a new page, add the following:

!define COMMAND_PATTERN {%m %p}
!define TEST_RUNNER {dotnetFitServer.exe}
!define PATH_SEPARATOR {;}
!path dotnetfit.dll
!path dotnet*.dll

|eg.Calculator|
|points?|
|false  |

This will run the included Calculator fixture in eg.dll that is included with the download, so you don’t have to write any code yourself.  Note that the FitNesse web server is a Java wiki, so you’ll need the JRE from sun

How to do Url Rewriting with just an HttpHandler (without the side-effects) – level 400

If you are interested in doing Url Rewriting with an HttpHandler instead of an HttpModule, then this is the example for you.  Suppose you are deriving a piece of information from Url, like a product code.  To process it, you have a page that accepts the product code as a querystring variable.  Look at the code below for how you can present a friendly Url while abstracting that away from how you actually process the request.  You can do postbacks and everything, and the Url will never revert back to the “ugly” Url.

 


    public class ProductHandler: IHttpHandler, IRequiresSessionState


    {


        public bool IsReusable


        {


            get { return true; }


        }


 


        public void ProcessRequest(HttpContext context)


        {


            context.Items[“originalQuerystring”] = context.Request.QueryString.ToString();
            context.Items[
“originalPathInfo”] = context.Request.PathInfo;


            string productCode = {some code to derive your product code};


            string page = “~/product.aspx”;


            string queryString = “productCode=” + productCode;


            foreach(string key in context.Request.QueryString.Keys)


            {


                if(key != productCode)


                {


                    queryString += string.Format(“&{0}={1}”, key, context.Request.QueryString[key]);


                }


            }


           


            context.RewritePath(context.Request.Path, string.Empty, queryString);


           


            Page hand = (Page)PageParser.GetCompiledPageInstance(page, context.Server.MapPath(page), context);


            // Listen for event to rewrite url back before the page renders.


            hand.PreRenderComplete += new EventHandler(hand_PreRenderComplete);


           


            hand.ProcessRequest(context);           


        }


 


        void hand_PreRenderComplete(object sender, EventArgs e)


        {


            HttpContext.Current.RewritePath(HttpContext.Current.Request.Path, 
               
HttpContext.Current.Items[“originalPathInfo”].ToString(), 
               
HttpContext.Current.Items[“originalQuerystring”].ToString());


        }


    }