• Javascript on-the-fly samenvoegen, minifyen en versionen

    Het samenvoegen van meerdere javascript files, en het minifyen van dezelfde javascript is een optimalisatie die flink effect kan hebben op de performance van je website; en een standaardadvies van optimalisatietools. Vandaar hier de techniek die wij gebruiken voor onze nieuwe mobiele website om javascript samen te voegen, te minifyen met YUI compressor, en automatisch te versionen.

    Welke javascript is nodig?
    Om op een willekeurige pagina aan te geven welke javascript benodigd is, kunnen we inhaken op het 'Page_Init()' event dat nog steeds bestaat in ASP.NET MVC. Dit draait voordat de view zal worden gerenderd. De syntax hiervoor is:

    // onderaan je .aspx of .master:
    <script runat="server">
        protected void Page_Init(object sender, EventArgs e)
        {
            ScriptHelper.RegisterScript("/js/jquery.js");
            ScriptHelper.RegisterScript("/js/global.js");
        }
    </script>

    Wanneer je bovenstaande code in je masterpage zet, kan je tevens per view een zelfde blokje toevoegen. Deze scripts worden dan ná de scripts in je masterpage toegevoegd (volgorde is nogal eens belangrijk bij javascript bestanden :-)).

    Continue reading »

  • Zoekbox live!

  • Zoekscherm dat dynamisch queries maakt met Expression Trees en MVC

    Naar aanleiding van de reactie van Jogai in Coding Glamour: Route constraints op QueryString parameters in ASP.NET MVC, een post over het mappen van een MVC zoekformulier naar een echte SQL query.

    Let's get it started
    Met behulp van het volgende model wordt een view getoond met daarop een formulier:

    // model
    public class ZoekformulierModel {
        public string Plaatsnaam { get; set; }
        public int PrijsVan { get; set; }
        public int PrijsTot { get; set; }
        public bool IndTuin { get; set; }
        
        /* wat code voor de opties in de selectlist */
    }


    <!-- view -->
    <form method="post" action="">
    <h1>Zoekformulier</h1>
    <table>
        <tr><th>Plaats</th><td><%=Html.TextBoxFor(m=>m.Plaatsnaam) %></td></tr>
        <tr><th>Prijs</th>
            <td><%=Html.DropDownListFor(m=>m.PrijsVan, Model.PrijsRange) %> - <%=Html.DropDownListFor(m=>m.PrijsTot, Model.PrijsRange) %></td></tr>
        <tr><th>Tuin?</th><td><%=Html.CheckBoxFor(m=>m.IndTuin) %></td></tr>
    </table>
    <input type="submit" value="Zoeken" />
    </form>

    http://www.100procentjan.nl/tweakers/zoek1.png

    Continue reading »

  • Route constraints op QueryString parameters in ASP.NET MVC

    ASP.NET MVC kent een vrij krachtige routing-engine om URL's te routen naar de actie die daarbij hoort. Naast puur URL's mappen kan je tevens constraints toevoegen om je routings wat te finetunen. Bijvoorbeeld praktisch voor de volgende situatie:

    /koop/amsterdam/appartement-12345-straat-1/fotos/
    -> moet naar ObjectController.Detail
    
    /koop/amsterdam/appartement-12345-straat-1/reageer/
    -> moet naar ObjectController.Contact

    Door een constraint toe te voegen, kan je onderscheid maken tussen deze twee URL's:

    // bijvoorbeeld
    routes.MapRoute(
        "object-contact",
        "{aanbod}/{plaats}/{type}-{id}-{adres}/{pagina}",
        /* ... */,
        new { pagina = @"reageer|bezichtiging" });
    // als pagina iets anders is dan reageer / bezichtiging matcht de route niet

    Probleem: wanneer je URL's van binnen als volgt zijn (omdat ASP.NET voor elke URL in je website opslaat of er een fysieke file voor is, en bij miljoenen unieke URL's is dat een huge leak dat niet automatisch wordt geflusht):

    /koop/?id=12345&pagina=reageer

    zijn constraints niet meer mogelijk, want dit wordt niet ondersteunt op QueryString parameters. Daarom: de QueryStringConstraint!

    Continue reading »

  • Mobile device detection

    Belangrijk onderdeel van ons nieuwe mobiele platform is uitvogelen welk device een gebruiker op dat moment gebruikt. Ben je mobiel met een viewport-breedte van < 600 px dan willen we je doorsturen naar onze mobiele site. En dan kom je terecht in de wondere wereld van User Agent parsing.

    Continue reading »

  • Bouw eens een API met WCF, deel 4: Beschikbaar via SOAP, XML en JSON

    Een API is geen API als er niet via verschillende protocollen tegenaan gepraat kan worden; iets wat in WCF volledig in config geregeld kan worden. In Visual Studio 2008 nog iets wat haast automatisch handwerk werd: de Configuration Editor was niet alleen alles behalve intuitief, maar genereerde ook nogal eens niet werkende configs. 2010 heeft daar echter verbeteringen in aangebracht, waardoor het configureren voor meerdere endpoints een breeze is.

    Continue reading »

  • Waarom Javascript zo awesome is


    ($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_]+
    ($=($_=!''+$)[_/_]+$_[+$])])()[__[_/_]+__
    [_+~$]+$_[_]+$](_/_)

    Via ADAMCECC

    Niet alleen awesome, want welke andere taal is zo flexibel met haar language-constructs? Tevens weer een quick reminder dat user input nooit te vertrouwen is. Wanneer je geïnteresseerd bent in beveiliging tegen dit soort aanvallen, kijk dan eens naar dit paper van Ryan Barnett: XSS Street Fight.

    Continue reading »

  • Nieuwe mobiele website, deel 1: Kickoff

    In de komende weken wil ik aandacht besteden aan het project waar ik op dit moment de lead voor ben: de herbouw van ons mobiele platform. Niet alleen puur technisch, maar ook een kijkje achter de deur wat betreft project management, planning en bepaalde keuzes. Vandaag deel 1: de kickoff.

    http://www.100procentjan.nl/tweakers/mobiel_oud.png

    Continue reading »

  • MSIL injection met PostSharp

    Wanneer je manager een nieuwe techniek ten strengste verbied met als argument 'we snappen je code normaal al niet, dit maakt het alleen maar erger' weet je dat je goud in handen hebt. Voor een eigen projectje om vals te spelen met Football Manager (waar ik later absoluut nog eens terug kom) had ik globaal de volgende situatie:

    public byte CurrentAbility
    {
        get {
            if (_mode == DbMode.Cached) {
                // in cached mode, hebben we een byte-array met alle waardes
                return _bytes[Offsets.CurrentAbility];
            } else {
                // anders lezen we via een helper-method
                return ProcessManager.ReadByte(_address + Offsets.CurrentAbility);
            }
        }
        set {
            // zelfde soort code voor de setter
        }
    }

    Leuk, neat, en vrij goed te lezen; probleem alleen dat ik een paar honderd properties heb, met een stuk of zeven verschillende types. Te veel werk. En aangezien je in eigen projecten toch helemaal los mocht gaan, leek een oplossing op basis van AOP me veel leuker. Nieuwe situatie:

    [FMEntity(Offsets.CurrentAbility)]
    public byte CurrentAbility { get; set; }

    Bovenstaande is best eenvoudig werkend te krijgen met PostSharp, een framework voor Aspect Oriented Programming in .NET. Een eenvoudige implementatie van bovenstaande is iets als:

    public class FMEntityAttribute : LocationInterceptionAspect
    {
        public FMEntityAttribute (int offset) {
            // doe wat
        }
        
        public override void OnGetValue( LocationInterceptionArgs args ) {
            if (args.Instance is byte) {
                // doe byte lezen enzo
            }
        }
        
        public override void OnSetValue( LocationInterceptionArgs args ) {
            // ongeveer hetzelfde
        }
    }

    Je kunt nu alle logica die toch steeds hetzelfde is, eenvoudig webabstraheren in een aparte file. Maar... té traag. In mijn geval werd het bepalen van de rating voor spelers ruim tien keer zo traag; door alle overhead. Oplossing? Zelf MSIL injecten!

    Continue reading »

  • Beeldmateriaal: funda 10 jaar!

    http://www.funda.nl/media/10597710/funda%20anno%202001.png
    Tien jaar bestaat funda alweer, en in al die jaren is er vrij veel veranderd. Het originele functioneel ontwerp voor héél funda telde bijvoorbeeld 9 hoofdstukken (inclusief 360 graden foto's!); 10 jaar later telt het FO voor alleen de 360 foto's maar liefst 23 hoofdstukken! Niet voor niets natuurlijk, want die tien jaar ontwikkeling; en die honderden pagina's aan extra FO's hebben tot veel moois geleid (ik schrijf hier elke dag een pagina over vol!). De afbeeldingen die hier eerder stonden zijn op verzoek verwijderd, dus derhalve een overzicht van 10 jaar funda aan de hand van de homepage.

    Continue reading »