in

Dé specialist in .NET trainingen en consultancy

Thomas Huijer

oktober 2007 - Posts

  • Keyword redirection voor ASP.NET 2.0

    De sourcecode van dit artikel is hier beschikbaar: KeywordRedirects.zip

    Deze keer niet iets wat ik voor een klant heb uitgezocht of wat in een training werd gevraagd, maar iets wat ik geresearched heb voor onze eigen website. Ik wilde een simpele manier om een pagina op te kunnen vragen op basis van een keyword. Zo wilde ik dat http://www.oosterkamp.nl/microsoftcsharp.aspx ook benaderbaar is op http://www.oosterkamp.nl/2124. Het Microsoft cursusnummer van de C# training is 2124. Deze nummers gebruiken wij intern en is dus handig om aan cursisten te laten zien welke vervolgtrainingen we hebben en wat de onderwerpen zijn die in die training aan bod komen. Ook is het handig om in geschreven communicatie simpele url's te kunnen gebruiken. Afijn, een lange inleiding om te komen tot de volgende probleemstelling:

    hoe redirect ik op een onderhoudbare manier een URL dat eindigt op een keyword naar een bestaande aspx-pagina?

    Mijn eerste idee was om UrlMappings in de web.config te gebruiken. Maar dat gaat niet werken. Een request voor een keyword heeft immers geen extensie en komt dus helemaal niet bij de ASP.NET Pipeline uit. Die wordt dus al door IIS afgehandeld met een prachtige 404. Dus dit werkt niet:

    <configuration>

      <system.web>

        <urlMappings>

          <add url="~/2124" mappedUrl="~/microsoftcsharp.aspx"/>

        </urlMappings>

      </system.web>

    </configuration>

    Dus er zit niets anders op dan tegen IIS te vertellen dat een 404 doorgestuurd moet worden naar een bepaalde pagina van de website. In IIS Manager (ik draai IIS 7 onder Vista), kun je voor elke Http error code instellen wat daar mee moet gebeuren.


    Ik heb de 404 geredirect naar de URL 404Redirect.aspx. Let op dat je het pad van de virtual directory ook meeneemt in de url.

     

    Dat is de eeste stap. Elke niet-bestaande pagina komt nu bij mijn 404Redirect..aspx uit. De volgende stap is om uit te vissen welk keyword werd meegegeven in het request. Het blijkt dat IIS dit meegeeft in de QueryString van 404Redirect.aspx. Als ik naar http://www.oosterkamp.nl/keyword browse, dan blijkt dit de volledige Url te zijn in 404Redirect.aspx:

    http://localhost/TestApp/404Redirect.aspx?404;http://localhost:80/TestApp/keyword

    Dus het keyword kunnen we er makkelijk af slopen: We zouden alles na de laatste slash kunnen nemen, maar ik heb er voor gekozen om het iets ingewikkelder te doen. Ik wilde ook support open houden voor keyword met slashes er in.

      string[] parms = Request.Url.Query.Split( ';' );

        if ( parms.Length == 2 && parms[ 0 ] == "?404" )

        {

          Uri uri = new Uri( parms[ 1 ] );

     

          string keyword = uri.PathAndQuery;

          keyword = keyword.Substring( Request.ApplicationPath.Length + 1 );

          Response.Write( keyword );

        }

    Op deze manier weet ik dus het keyword dat in de url opgegeven werd. Volgende stap was om een onderhoudbare manier te verzinnen om een mapping te maken tussen een keyword en een url. Ik besloot om dat in de web.config op te nemen. Dat is de meest aangewezen plek er voor. Het zou wel zorgen voor een application restart als we een keyword zouden toevoegen, maar voor onze site is dat geen wezenlijk probleem. In .NET 2.0 is het veel eenvoudiger geworden om custom configuration sections te maken. Er zijn verschillende classes waar je van kan afleiden: ConfigurationElement, ConfigurationSection, ConfigurationElementCollection etc. Dit is wat ik in m'n web.config wilde hebben:

      <configSections>

        <section name="oosterkamp.web" type="Oosterkamp.Web.OosterkampWebSection" />

      </configSections>

      <oosterkamp.web>

        <keywordRedirects>

          <add keyword="bla" redirect="~/default.aspx" />

          <add keyword="2124" redirect="~/microsoftcsharp.aspx" />

        </keywordRedirects>

      </oosterkamp.web>

    Om dit te realiseren heb ik een aantal classes gemaakt. Ten eerste een class die de <add keyword="" redirect="" /> representeert:

      public class KeywordRedirectionElement: ConfigurationElement

      {

        [ConfigurationProperty( "keyword" )]

        public string Keyword

        {

          get { return (string) base["keyword"]; }

        }

     

        [ConfigurationProperty( "redirect" )]

        public string Redirect

        {

          get { return (string) base["redirect"]; }

        }

    Je hoeft alleen maar af te leiden van ConfigurationElement en properties te maken met het ConfigurationPropertyAttribute. Dat mapt de property en het xml-attribuut op elkaar.

    public class KeywordRedirectionCollection : ConfigurationElementCollection

      {

        public override ConfigurationElementCollectionType CollectionType

        {

          get

          {

            return ConfigurationElementCollectionType.AddRemoveClearMap;

          }

        }

     

        protected override ConfigurationElement CreateNewElement()

        {

          return new KeywordRedirectionElement();

        }

     

        protected override object GetElementKey( ConfigurationElement element )

        {

          return (element as KeywordRedirectionElement).Keyword.ToLower();   

        }

     

        public KeywordRedirectionElement this[ int index ]

        {

          get

          {

            return (KeywordRedirectionElement) BaseGet( index );

          }

          set

          {

            if ( BaseGet( index ) != null )

              BaseRemoveAt( index );

            BaseAdd( index, value );

          }

        }

     

        public KeywordRedirectionElement this[ string keyword ]

        {

          get

          {     

            return (KeywordRedirectionElement) this.BaseGet( keyword.ToLower() );

          }

        }

      }

    De collection is wat lastiger. Je leidt af van ColfigurationElementCollection en implementeert een aantal methods/properties:

    • CreateNewElement
      Tsja, wat zou ie doen? :-)
    • GetElementKey
      Bepaalt de key per item.
    • CollectionType
      Bepaalt wat voor soort collectie het is. In dit geval een add/remove/clear collectie.
    • Een indexer om op index de collectie te kunnen bevragen.
    • Een indexer om een item op te kunnen zoeken op keyword.

    En als laatste een class die de section representeert:

      public class OosterkampWebSection: ConfigurationSection

      {

        [ConfigurationProperty( "keywordRedirects" )]

        [ConfigurationCollection( typeof( KeywordRedirectionCollection ),

                                   AddItemName="add", RemoveItemName="remove" )]

        public KeywordRedirectionCollection KeywordRedirects

        {

          get

          {

            return (KeywordRedirectionCollection) base[ "keywordRedirects" ];

          }

        }

      }

    Dat is alle benodigde code om de keywords in de web.config op te nemen. Als laatste dan de code waarmee we in de 404Redirect.aspx uit de web.config halen naar welke pagina we moeten redirecten:

      protected void Page_Load( object sender, EventArgs e )

      {

        OosterkampWebSection section =

          (OosterkampWebSection) WebConfigurationManager.GetSection( "oosterkamp.web" );

     

     

        string[] parms = Request.Url.Query.Split( ';' );

        if ( parms.Length == 2 && parms[ 0 ] == "?404" )

        {

          Uri uri = new Uri( parms[ 1 ] );

     

          string path = uri.PathAndQuery;

          path = path.Substring( Request.ApplicationPath.Length + 1 );

          KeywordRedirectionElement element = section.KeywordRedirects[ path ];

          if ( element != null )

            Response.Redirect( element.Redirect );

          else

            Response.StatusCode = 404;

        }

    That's all. Hiermee kunnen we nu eenvoudig keyword redirects toevoegen aan onze web.config om zo gebruikers van onze site makkelijk te onthouden urls te kunnen geven in onze advertenties bijvoorbeeld. Of om zelf op een eenvoudige manier bepaalde pagina's op te kunnen vragen.

    Ennuh...voor iemand er wat over zegt: ik weet het, het werkt op onze site. Dit was maar een research-projectje. Maar dat duurt niet lang meer voor het ook echt op onze site werkt.

    Posted okt 20 2007, 03:03 by Thomas with no comments
    Filed under: ,
  • PostSharp: Aspect Oriented Programming in .NET

    Ik weet niet meer hoe, maar ik kwam toevallig het volgende product tegen op het Internet: Post#. Post# is een lightweight AOP framework voor .NET. Het gebruikt een post-build process om de door de compiler gegenereerde assembly te modificeren. Het resultaat is dat je op een hele eenvoudige manier (door het toevoegen van attributes), de functionaliteit van je applicatie kan aanpassen. Aspect Oriented Programming in .NET dus...errug cool.

    Ik raad iedereen aan om deze 7 minuten durende video te bekijken. Dat laat het beste zien wat het product doet en welke kracht het heeft. Ik weet zeker dat ik dit ga gebruiken voor een product waar ik samen met een amerikaanse klant van ons aan werk. Nou ja, heb gewerkt en weer ga werken. Het ligt nu even stil. Maar dat komt wel weer.

  • Outlook Calendar Search v0.1

    Voor een collega heb ik een simpele Outlook add-in gemaakt, waarmee je in de Outlook Calender kunt zoeken naar afspraken met een bepaalde zoekterm er in. Het filtert je afspraken zodat je bijvoorbeeld snel kunt zien op welke momenten je met een klant hebt afgesproken. Dat werkt veel sneller dan zoeken in je afspraken. Je hebt gelijk een visueel overzicht.

    De add-in is geschreven in C# met Visual Studio 2008 beta 2 en VSTO.

    Liefhebbers kunnen deze Outlook add-in downloaden. En ik weet het: er zit geen installer bij. Het is ook puur bedoeld als demo. Commentaar is welkom!

  • Eindelijk source code!

    Microsoft heeft besloten om de source-code van het .NET Framework te gaan releasen. Goed idee, lijkt me. Ik, met m'n jarenlange Delphi achtergrond, vond het altijd nogal hinderlijk dat je geen source-code had van de classes die je in je applicaties gebruikt. Van de Delphi VCL had je tenminste alle sources. Maar goed, met Reflector kwam je natuurlijk al een heel eind, maar locale variabele namen miste je bijvoorbeeld. Met de komst van Visual Studio 2008 en het 3.5 Framework is dat ook weer opgelost. Hier kun je er meer over lezen op de blog van Scott Guthrie.