This month I’ve been going pretty hard core about learning ASP.NET and I was having a lot of difficulty with playing with the ASPX view engine. I’m already fairly familiar with HTML and CSS, but now I have to learn these new ASP.NET controls? Why can’t I just stick to the HTML and CSS I know and enjoy working with?
Well it turns out I can… I don’t need to learn about the complex data binding of a GridView or how an ASP:TextBox converts to a plain ol’ input tag wrapped in span tags. I’ve been heavily studying the work from the project we worked on during the Nothin’ But .NET boot camp and reading up on the MSDN documentation on inlining aspx.
I like it… C’mon doesn’t this….

<h1>Available Slips</h1>          
  <table>
      <thead>
          <tr>
              <td>Location Name</td>
              <td>Dock Name</td>
              <td>Slip Width</td>
              <td>Slip Length</td>
          </tr>
      </thead>            
  <&#37; foreach ( SlipDisplayDTO item in ViewLuggage.ClaimFor(ViewLuggageTickets.AvailableSlips) )
  {&#37;>
      <tr>
          <td><&#37;= item.LocationName &#37;></td>
          <td>
              <a href='<&#37;= WebViews.DockView.Name( ) &#37;>?<&#37;= PayloadKeys.DockId
                &#37;>=<&#37;= item.DockId &#37;>'>
                  <&#37;= item.DockName &#37;>
              </a>
          </td>
          <td><&#37;= item.Width &#37;></td>
          <td><&#37;= item.Length &#37;></td>        
      </tr>
  <&#37; } &#37;>                    
  </table>

Seem a lot more readable then this…

<asp:Repeater ID="uxSlipsRepeater" runat="server">
  <HeaderTemplate>
  <table>
  <thead>
      <tr>
          <td>Dock Name</td>
          <td>Slip Width</td>
          <td>Slip Length</td>
      </tr>
  </thead>
  </HeaderTemplate>
  <ItemTemplate>
      <tr>
          <td>
  <a href='DockView.aspx?<&#37;= PayLoadKeys.DockId &#37;>=<&#37;#
    ((SlipDisplayDTO)Container.DataItem).DockId &#37;>'>
  <&#37;# Transform.From(Container.DataItem).AndConvertItToAn<SlipDisplayDTO>().DockName &#37;>
  </a>
          </td>
          <td><&#37;# Transform.From(Container.DataItem).AndConvertItToAn<SlipDisplayDTO>().Width
            &#37;></td>
          <td><&#37;# Transform.From(Container.DataItem).AndConvertItToAn<SlipDisplayDTO>().Length
            &#37;></td>
      </tr>
  </ItemTemplate>
  <FooterTemplate>
  </table>
  </FooterTemplate>
  </asp:Repeater>

The extra asp namespaces appended to all the controls just seem like noise. The explicit casting from Container.DataItem to the type actually contained seems like extra work. I suppose you could write all this out in an item data bound event handler. But it just looks like noise, noise noise… Then when you actually look at the HTML that’s spit out it loaded with more noise…

For example:

<input 
      name="ctl00$ContentPlaceHolder2$uxUserNameTextBox" 
      type="text" 
      id="ctl00_ContentPlaceHolder2_uxUserNameTextBox" />

Versus:

<input name="uxUserNameTextBox" type="text" />

Well all of this can be avoided. But you’re going to have to get just a little bit deeper, and here’s how. Everything you need to know is in HttpContext. Yup!

Instead of dropping an ASP:TextBox on the page try an input element and parse out the value in the input element from the HttpContext.Current.Request.Params. This is a NameValueCollection that has all the Http Headers that were sent along the trip to the server AKA The Payload.

For my current school assignment I’m currently flushing out the concept of an HttpGateway, where all traffic comes in and all traffic goes out. Currently this is just wrapping and HttpContext but with an interface that works better for me as a client of it. I don’t need to see everything available in the HttpContext (which is a lot!).

Next up, take advantage of the HttpContext.Items collection. This is a collection of objects which you can load up with extra information to pass on down the pipeline. Consider the concept of view luggage, where luggage is issued a ticket when you drop it off. You can then claim that luggage using the same luggage ticket.

What does this mean, you can have your presenters, controllers, commands (whatever) drop off luggage to be carried to the view. You can then have your views claim that luggage with the luggage ticket. (Take a look back at the first bit of HTML markup in this post.)

The HttpContext.Items collection is a dictionary for objects. Using strongly typed luggage tickets you can make that the key, and the actual luggage the value to store in the items collection. The HttpContext then becomes the airplane, carrier or transporter that hauls your luggage from your presenter, controller, command (whatever) to the view.

For the quick and dirty here’s the code that describes what I’m talking about:

public class ViewLuggageTransporter< Luggage > : IViewLuggageTransporter< Luggage > {
        public ViewLuggageTransporter( IViewLuggageTicket< Luggage > key ) : this( key, HttpContext.Current.Items ) {}

        private ViewLuggageTransporter( IViewLuggageTicket< Luggage > key, IDictionary items ) {
            _ticket = key;
            _items = items;
        }

        public Luggage Value() {
            foreach ( DictionaryEntry entry in _items ) {
                if ( entry.Key.Equals( _ticket ) ) {
                    return ( Luggage )entry.Value;
                }
            }
            return default( Luggage );
        }

        public void Add( Luggage value ) {
            _items.Add( _ticket, value );
        }

        private readonly IViewLuggageTicket< Luggage > _ticket;
        private readonly IDictionary _items;
    }

    public class ViewLuggage {
        public static IViewLuggageTransporter< T > TransporterFor< T >( IViewLuggageTicket< T > ticket ) {
            return new ViewLuggageTransporter< T >( ticket );
        }

        public static T ClaimFor< T >( IViewLuggageTicket< T > ticket ) {
            return new ViewLuggageTransporter< T >( ticket ).Value( );
        }
    }

To parse out the value submitted in a request you can create mappers to parse out the values for each control. In the code below each of the string literals prefixed with a “ux” represents the name of the html control that was on the page.

public class UpdateRegistrationPresentationMapper : IUpdateRegistrationPresentationMapper {
        public UpdateCustomerRegistrationDTO MapFrom( IHttpRequest input ) {
            return new UpdateCustomerRegistrationDTO(
                input.ParsePayloadFor( PayloadKeys.CustomerId ),
                input.ParsePayloadFor( PayloadKeys.For( "uxUserNameTextBox" ) ),
                input.ParsePayloadFor( PayloadKeys.For( "uxPasswordTextBox" ) ),
                input.ParsePayloadFor( PayloadKeys.For( "uxFirstNameTextBox" ) ),
                input.ParsePayloadFor( PayloadKeys.For( "uxLastNameTextBox" ) ),
                input.ParsePayloadFor( PayloadKeys.For( "uxPhoneNumberTextBox" ) ),
                input.ParsePayloadFor( PayloadKeys.For( "uxCityTextBox" ) )
                );
        }
    }

Next up, figuring out a cleaner way to implement authorization and authentication without having to rely on the FormsAuthentication class. So far my spiking of Forms Auth looks something like the code below… *Please do not use the code below. I was just trying to understand how forms auth works and this is not a great example of how you should use it.

public void AuthenticateHttpRequest( ) {
            HttpCookie cookie = GetCookieFrom( HttpContext.Current );
            if ( null != cookie ) {
                BindPrincipalToThreadUsing( _mapper.MapFrom( FormsAuthentication.Decrypt( cookie.Value ) ) );
            }
        }

        private HttpCookie GetCookieFrom( HttpContext context ) {
            return context.Request.Cookies[ FormsAuthentication.FormsCookieName ];
        }

        private void BindPrincipalToThreadUsing( CustomerCookieCredentials credentials ) {
            IIdentity identity = new CustomerIdentity( credentials.Username, credentials.Username );
            HttpContext.Current.User = new GenericPrincipal( identity, new string[] {"customer"} );
        }

        private void AddAuthenticationTicket( ) {
            FormsAuthenticationTicket ticket =
                new FormsAuthenticationTicket( 1, "mo", DateTime.Now, DateTime.Now.AddMinutes( 20 ), false, "2" );
            string cookieValue = FormsAuthentication.Encrypt( ticket );
            HttpContext current = HttpContext.Current;
            current.Response.Cookies.Add( new HttpCookie( FormsAuthentication.FormsCookieName, cookieValue ) );

            IIdentity identity = new CustomerIdentity( "mo", "2" );
            current.User = new GenericPrincipal( identity, new string[] {"customer"} );
        }
comments powered by Disqus