Blog moved to http://www.andrevdm.com/

Sunday, 16 February 2014

Parsing s-expressions in Clojure

Introduction


This is a quick look at parsing in clojure. First using instaparse and then writing the lexer and parser by hand. The comparison should illustrate how great instaparse is but also show that writing a simple lexer & parser is not as complex as some would think.

BTW this is my first clojure project so I may have got some of the idioms in the code incorrect. I'll update the code samples based on feedback here and on the project repo in github :)

The demo project


To demonstrate instaparse I'll be implementing a simple external DSL. The DSL should have the following characteristics
  1. Expressions written as sexprs
  2. External DSL - I'm not interested in using the clojure reader to read the sexpr for this demo
  3. Constrained - functions can only be defined in clojure not in the DSL itself. The functions available to the DSL must be strictly controlled.
All code is in the github repository (https://github.com/andrevdm/blog-clojure-sexpr-parse)

Instaparse

Using instaparse

Instaparse (https://github.com/Engelberg/instaparse) is a clojure library for generating a parser (and lexer) from a EBNF/ABNF. It is one of the easiest parser generators I've used, I highly recommend giving it a try.

 The grammar

The instaparse page has a nice introduction to the grammar syntax. Start there if you are not familiar with EBNF.

Here is the grammar that I'll be parsing

   S = (expression )*
    expression = list | vector | atom
    list = <'('> (expression )* <')'>
    vector = <'['> (expression )* <']'>
    atom = number | string | name
    number = #'\d+'
    string = <'"'> #'[^\"]+' <'"'>
    name = #'[a-zA-Z\+-]([0-9a-zA-Z\+-]*)'
    ws = #'\s+'




This is pretty standard EBNF. Some things to note

  1. Wrap an element in angle brackets to remove it from the output e.g.
  2. Match literal characters with single quotes. e.g. '('
  3. Regular expressions using #'regex'
  4. Remember to escape regex characters correctly. See the code example for the correct escaping

Again the instaparse page has a nice introduction that covers all of this.

The output parse tree


The output parse tree from instaparse can be in hiccup or enliven format. I'll be using the default hiccup format.

As an example here is the output for "(+ 1 2 3) 4"

   [:S
    [:expression
     [:list
      [:expression [:atom [:name "+"]]]
      [:expression [:atom [:number "1"]]]
      [:expression [:atom [:number "2"]]]
      [:expression [:atom [:number "3"]]]]]
    [:expression [:atom [:number "4"]]]]


Instaparse can visualise a parse tree using graphviz and rhizome (see https://github.com/Engelberg/instaparse#visualizing-the-tree). E.g. for the parse tree above you get this



Interpreting the parse tree

There are several ways to interpret the output from instaparse, e.g. using zippers or using the built in instaparse transformation function. However I chose to use simple recursive functions since it is so simple.

   (defmulti run (fn [s] (nth s 0)))
   (defmethod run :S [[s & es]] (last (doall (map run es))))
   (defmethod run :expression [[e t]] (run t))
   (defmethod run :atom [[a t]] (run t))
   (defmethod run :number [[n val]] (read-string val))
   (defmethod run :string [[s val]] val)
   (defmethod run :vector [[v & vs]] (vec (map run vs)))
   (defmethod run :name [[n & nn]] (first nn))
   (defmethod run :list [[l n & ls]] (let [args (map run ls)]
                                        (apply (methods (run n)) args)))



The multimethod's dispatch function gets the first item from each vector. Look at the parse tree above, you'll see that this will always be the type of the current element (:S or :expression or :number etc)

Each method then is responsible for destructuring its element type. E.g. the :number method must parse the number and return a string. The :vector method must return a vector. Each method calls the run multimethod recursively to get the lowest level atom

Notice that the :S method calls last on doall, which is called to force evaluation of the whole lazy seq. last is called to get the last value. I.e. the parser will return the last value evaluated just as clojure would.

The :list method is where the interpreter actually "runs" functions called by the DSL.



   (defmethod run :list [[l n & ls]] (let [args (map run ls)]
                                         (apply (methods (run n)) args)))




The parameters [ [l n & ls] ]  destructure the incoming element into
  1.  l = the :list
  2.  n = the name of the function as a :name element
  3.  s = the method arguments

Remember that a list is executed by treating the first expression as the function and the rest as the arguments to that function.


Once we have the arguments they must be evaluated by calling run for each argument
   (map run ls)

We get the name of the function to run
   (run n)

We look up the actual function to call in the methods map. It is this map that lets us control exactly which functions can be called. All together it looks like this
   (let [args (map run ls) (apply (methods (run n)) args)))


Full sample code

Here is the full code for the DSL parser and interpreter using instaparse
(ns cljsexp-instaparse.core
 (:require [instaparse.core :as insta]))

(def parse
 (insta/parser
 "S = (expression )*
 expression = list | vector | atom
 list = <'('>  (expression )* <')'>
 vector = <'['> (expression )* <']'>
 atom = number | string | name
 number = #'\\d+'
 string = <'\"'> #'[^\\\"]+' <'\"'>
 name = #'[a-zA-Z\\+-]([0-9a-zA-Z\\+-]*)'
 ws = #'\\s+'"))

(def methods
 {"+" +
 "-" -
 "*" *
 "/" /
 "++" inc
 "--" dec
 "prn" println})

(defmulti run (fn [s] (nth s 0)))
(defmethod run :S [[s & es]] (last (doall (map run es))))
(defmethod run :expression [[e t]] (run t))
(defmethod run :atom [[a t]] (run t))
(defmethod run :number [[n val]] (read-string val))
(defmethod run :string [[s val]] val)
(defmethod run :vector [[v & vs]] (vec (map run vs)))
(defmethod run :name [[n & nn]] (first nn))
(defmethod run :list [[l n & ls]] (let [args (map run ls)]
                                       (apply (methods (run n)) args)))

Conclusion - instaparse

Instaparse is amazing. It makes writing a parser very easy indeed. A simple sexp parser and interpreter in less that 40 lines of clojure is a great result.


A simple recursive descent parser


Writing the lexer and parser by hand is an interesting exercise as it shows that its not too hard to do. However in my opinion it also shows how much simpler instaparse makes things even for simple projects.

For what it is worth note that there is no mutable state in this code. All the functions are pure. This made testing very easy.

Lexing



Lexing or tokenising a string is the process of converting the characters from the source code into higher level tokens (equivalent to taking individual letters and making words).

E.g. taking this character stream

 |   |   |   |   |   |   |   |   |   |   |   |   |
 | ( | i | f |   | ( | a | n | d | ( | a | b | c |

 |   |   |   |   |   |   |   |   |   |   |   |   |
And creating these tokens

 left-paren, if, left-paren, and, left-paren, abc

Each token has meta-data associated with it. Such as the line and column in the source file and the type of token (string vs name vs paren etc).

Tokenising the input means that the parser does not need to deal with individual characters but rather can work with higher level tokens. This greatly simplifies the design as the concerns of lexing the input and parsing the resulting tokens can be separated. In a recursive descent parser you could lex the next token on demand rather than lex everything first as I have here.

NB remember that the output of the tokeniser is a flat list of tokens. No meaning has yet been inferred from the source code


In the code above each token has the following clojure structure

{:type :xxx,
 :val xxx,
 :line xxx,
 :col xxx,
 :expressions []}


Each token has a
  1. Type (e.g. name/string/list)
  2. Value (e.g. the numeric or string value of the text)
  3. The line and column number that the token started in the source file
  4. A place holder for nested expressions


Matching the next token


(def tokenMap {:byChar { \( :lparen
                         \) :rparen,
                         \[ :lbracket,
                         \] :rbracket}
               :byRegex { #"'" parseString
                          #"\d+" parseNumber
                          #"[a-zA-Z\+\-\*\\\/\?_\$\<\>=]" parseName
                          #";" parseComment }})







Here there are two maps. The first identifies single character tokens such as brackets or parentheses. The second uses a regular expression to match the first letter of a token and defines the function that gets called to tokenise it.

For example if the tokeniser gets a semi-colon it calls the parseComment function which calls the parseRegex helper function. Below you can see these two methods. When a semi-colon is found the regex will match to the end of the line and the current position will be moved (moveRight) by the number of matched characters.

(defn parseRegex [state, typeName, token, re]
  (let [s (subs (currentLine state) (:col state))
        val (re-find re s)]
    ;Does the remainder of the line match the regex - it should!
    (if val

      (assoc
          (moveRight state (count val))
        :token token
        :val val)

      (throw (Exception. (str "Failed to parse " typeName))))))

(defn parseComment [state]
  (parseRegex state "comment" :comment #";.*"))




Moving in the input stream

Below is the moveRight function which moves right in the input stream. Notice that this takes the current position in a state argument and returns a new state as a result. I.e. nothing is mutated.

(defn moveRight [state by]
  "Move current position  1 char to the right, roll over to next line if required"
  (let [updated (assoc state :col (+ (:col state) by) )]
    (let [line (currentLine state)]
      (if (< (:col updated) (count line))

        ;Still space on current line, return it
        updated

        ;Move to next line
        (assoc
          state
          :col 0
          :line (inc (:line state)))))))



Running the tokeniser


Finally here are the two functions that control the tokenising

(defn- nextToken [state]
  "Gets the next token"
  (let [c (currentChar state)]
    (cond

     (nil? c) (clearToken state)

     ;Ignore white space
     (Character/isSpaceChar c) (recur (moveRight state 1))

     ;Check if a token can be found in the token map by character
     :else  (if-let [token ((:byChar tokenMap) c)]
              (assoc (moveRight state 1) :token token :val c)

              ;Nothing found so now search by regex
              ; Get the function associated with the first regex that matches and call that
              (if-let [r (first (filter #(re-matches (% 0) (str c)) (:byRegex tokenMap)))]
                ((r 1) state)
                (throw (Exception. (str "dont understand next token - " c state))))))))


(defn- tokenise [state]
  (loop [nextState (nextToken state), tokens []]
    (if (= :none (:token nextState))
      tokens
      (recur
       (nextToken nextState)
       (conj tokens {:line (:line nextState),
                     :col (:col nextState),
                     :val (:val nextState),:type (:token nextState)})))))





nextToken gets 1 next token
tokenise repeatedly calls nextToken until the whole input stream has been tokenised

Parsing


At this point the lexer has lexed the entire file and the parser can now parse the token stream.

The function that runs the parser is parseAll

(defn- parseAll [allTokens]
  (loop [expressions [], tokens allTokens]
    (let [r (parseExpression (first tokens) (rest tokens))]
      (if (= 0 (count (:expr r)))
        expressions
        (recur (conj expressions (:expr r)) (:tokens r))))))





But all the work is actually done in parseExpression. This is quite a long function that is just a large case statement. Not pretty but reasonably clear, hopefully.

(defn- parseExpression [token tokens]
    (case (:type token)
      (nil '()) [nil tokens]

      :name {:expr {:type :name,
                    :val (:val token),
                    :line (:line token),
                    :col (:col token),
                    :expressions []}
             :tokens tokens}

      :string {:expr {:type :string,
                      :val (:val token),
                      :line (:line token),
                      :col (:col token),
                      :expressions []}
               :tokens tokens}

      :number {:expr {:type :number,
                      :val (read-string (:val token)),
                      :line (:line token),
                      :col (:col token),
                      :expressions []}
               :tokens tokens}

      (:lparen :lbracket) (let [grp (if (= :lparen (:type token))
                                      {:start :lparen, :end :rparen, :type :list}
                                      {:start :lbracket, :end :rbracket, :type :vector})]
                            (loop [expressions []
                                   [loopToken & loopTokens] tokens]

                              (let [type (:type loopToken)]
                                (cond
                                 (or (nil? token) (= '() token)) (throw (Exception. (str "EOF waiting for :rparen")))

                                 (= (:end grp) type) {:expr {:type (:type grp)
                                                             :val (:type grp)
                                                             :line (:line token)
                                                             :col (:col token)
                                                             :expressions expressions}
                                                      :tokens loopTokens}

                                 :else (let [r (parseExpression loopToken loopTokens)]
                                         (recur (conj expressions (:expr r)) (:tokens r)))))))))





This function is switching on the first token and returning the matched token and the remaining tokens. For example when it gets a :name it returns an :expr of type :name and returns the rest of the tokens.

When parseExpression gets lparen or lbracket it will recursively loop through the tokens until the end of the list or vector, returning the tokens that have not been consumed.

Interpreting the syntax tree

Evaluating the syntax tree is similar to the code in the instaparse Version

(declare eval)

(defmulti run (fn [x] (:type x)))
(defmethod run :string [e] (:val e))
(defmethod run :number [e] (:val e))
(defmethod run :name [e] (:val e))
(defmethod run :vector [e] (vec (map run (:expressions e))))
(defmethod run :list [e] (do
                           (let [f (run (first (:expressions e)))
                                 args (map run (rest (:expressions e)))]
                             (apply (get funcs f) args))))
(defmethod run :default [e] (println "unknown: " e))


(defn eval [[car & cdr]]
  (let [r (run car)]
    (if (empty? cdr)
      r
      (recur cdr))))




Again a multimethod is used to recursively evaluate the syntax tree and as with the instaparse code only functions defined in the 'funcs' map may be executed.

Conclusion - hand written


The hand written lexer and parser are a lot longer than just using instaparse. However it is not that complicated to do manually. Personally I'll be using instaparse for 99% of my Clojure DSL needs but it is always good to know how to do it manually.

The full source code

(ns cljsexp-simple.core


(def funcs {"prn" println
            "+" +})

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn currentLine [state]
  "Gets the current line"
  (get (:code state) (:line state)))


(defn currentChar [state]
  "Gets the current charater"
  (get (currentLine state) (:col state)))


(defn moveRight [state by]
  "Move current position  1 char to the right, roll over to next line if required"
  (let [updated (assoc state :col (+ (:col state) by) )]
    (let [line (currentLine state)]
      (if (< (:col updated) (count line))

        ;Still space on current line, return it
        updated

        ;Move to next line
        (assoc
            state
          :col 0
          :line (inc (:line state)))))))


(defn parseRegex [state, typeName, token, re]
  (let [s (subs (currentLine state) (:col state))
        val (re-find re s)]
    ;Does the remainder of the line match the regex - it should!
    (if val

      (assoc
          (moveRight state (count val))
        :token token
        :val val)

      (throw (Exception. (str "Failed to parse " typeName))))))


(defn parseName [state]
  (parseRegex state "name" :name #"[a-zA-Z\+\-\*\\\/\?_\$\<\>=]+"))

(defn parseComment [state]
  (parseRegex state "comment" :comment #";.*"))

(defn parseString [state]
  (parseRegex state "string" :string #"'[^']+'"))

(defn parseNumber [state]
  (parseRegex state "number" :number #"\d+"))

(def tokenMap {:byChar { \( :lparen
                         \) :rparen,
                         \[ :lbracket,
                         \] :rbracket}
               :byRegex { #"'" parseString
                          #"\d+" parseNumber
                          #"[a-zA-Z\+\-\*\\\/\?_\$\<\>=]" parseName
                          #";" parseComment }})

(defn clearToken [state]
  (assoc state
    :token :none
    :val :none))

(defn- nextToken [state]
  "Gets the next token"
  (let [c (currentChar state)]
    (cond

     (nil? c) (clearToken state)

     ;Ignore white space
     (Character/isSpaceChar c) (recur (moveRight state 1))

     ;Check if a token can be found in the token map by character
     :else  (if-let [token ((:byChar tokenMap) c)]
              (assoc (moveRight state 1) :token token :val c)

              ;Nothing found so now search by regex
              ; Get the function associated with the first regex that matches and call that
              (if-let [r (first (filter #(re-matches (% 0) (str c)) (:byRegex tokenMap)))]
                ((r 1) state)
                (throw (Exception. (str "dont understand next token - " c state))))))))


(defn- tokenise [state]
  (loop [nextState (nextToken state), tokens []]
    (if (= :none (:token nextState))
      tokens
      (recur
       (nextToken nextState)
       (conj tokens {:line (:line nextState),
                     :col (:col nextState),
                     :val (:val nextState),:type (:token nextState)})))))

(defn- parseExpression [token tokens]
    (case (:type token)
      (nil '()) [nil tokens]

      :name {:expr {:type :name,
                    :val (:val token),
                    :line (:line token),
                    :col (:col token),
                    :expressions []}
             :tokens tokens}

      :string {:expr {:type :string,
                      :val (:val token),
                      :line (:line token),
                      :col (:col token),
                      :expressions []}
               :tokens tokens}

      :number {:expr {:type :number,
                      :val (read-string (:val token)),
                      :line (:line token),
                      :col (:col token),
                      :expressions []}
               :tokens tokens}

      (:lparen :lbracket) (let [grp (if (= :lparen (:type token))
                                      {:start :lparen, :end :rparen, :type :list}
                                      {:start :lbracket, :end :rbracket, :type :vector})]
                            (loop [expressions []
                                   [loopToken & loopTokens] tokens]

                              (let [type (:type loopToken)]
                                (cond
                                 (or (nil? token) (= '() token)) (throw (Exception. (str "EOF waiting for :rparen")))

                                 (= (:end grp) type) {:expr {:type (:type grp)
                                                             :val (:type grp)
                                                             :line (:line token)
                                                             :col (:col token)
                                                             :expressions expressions}
                                                      :tokens loopTokens}

                                 :else (let [r (parseExpression loopToken loopTokens)]
                                         (recur (conj expressions (:expr r)) (:tokens r)))))))))


(defn- parseAll [allTokens]
  (loop [expressions [], tokens allTokens]
    (let [r (parseExpression (first tokens) (rest tokens))]
      (if (= 0 (count (:expr r)))
        expressions
        (recur (conj expressions (:expr r)) (:tokens r))))))


(defn parse [code]
  (let [tokens (tokenise {:code code, :line 0, :col 0, :val :none, :token :none})
        result (parseAll tokens)]
    result))


;;;;;;;;;;;;;;;;;;;;;;;

(declare eval)

(defmulti run (fn [x] (:type x)))
(defmethod run :string [e] (:val e))
(defmethod run :number [e] (:val e))
(defmethod run :name [e] (:val e))
(defmethod run :vector [e] (vec (map run (:expressions e))))
(defmethod run :list [e] (do
                           (let [f (run (first (:expressions e)))
                                 args (map run (rest (:expressions e)))]
                             (apply (get funcs f) args))))
(defmethod run :default [e] (println "unknown: " e))


(defn eval [[car & cdr]]
  (let [r (run car)]
    (if (empty? cdr)
      r
      (recur cdr))))




Thursday, 13 February 2014

Fixing assembly version conflicts in .net with AsmSpy

Occasionally you will get assembly version conflicts when building / running .net projects. Here is a quick overview of how to fix



Using AsmSpy

Using AsmSpy is the easiest way to find assembly version conflicts.

Get it from: https://github.com/mikehadlow/AsmSpy

Run it on the build output directory. E.g.
  AsmSpy c:\Projects\SomeProject\bin\Debug

It will display a list of references and the assemblies that use them.


For example

Reference: log4net
   1.2.13.0 by ABCD
   1.2.13.0 by XYZ
   1.2.12.0 by EEE

Here you can see that EEE is expecting a lower version of log4net that the rest of the assemblies.

This makes it very easy to spot the errors. 


Checking for errors manually

You can also manually check for errors by looking at the output window after a build. Using AsmSpy is a lot easier though



Sunday, 11 August 2013

Upgrading to ANTLR 4 with C#

Upgrading from ANTLR 3.x to ANTLR 4 was pretty painless. Here are the changes I needed to make to get it all working

  1. Get ANTLR 4 from nuget (you will need to allow pre-release versions for now)
  2. Change your ANTLR build script to reference the new ANTLR JAR. The JAR is included in the nuget. This what my build script looks like
        set classpath=C:\xxx\packages\Antlr4\tools\antlr4-csharp-4.1-SNAPSHOT-complete.jar
        java org.antlr.v4.Tool xxx.g4 -Dlanguage=CSharp_v4_0
  3. Rename grammars from .g to .g4
  4. Remove the options block or change it to match your C# version selection
       options
       {
          language=CSharp_v4_0;
       }
  5. Tokens should be comma delimited not semicolon delimited
  6. Always use a $ when referring to parameters, return variables, tokens etc. ANTLR 3.4 did not always enforce this so if you forgot it in a few places you will need to fix them
  7. You can still check if a optional token exists just be sure to use the .ctx. E.g. use this
       if( $i.ctx != null )
  8. You may get errors when using properties on matched tokens. Parentheses will fix this. E.g.
       ($i).Text
  9. Use “-> skip” rather than “{$channel=HIDDEN}”
  10. Use “.*?” rather than “options {greedy=false;}”

Hope this helps someone

Tuesday, 28 May 2013

Building for mono and Microsoft .NET

Recently I wanted to build my project on mono and Microsoft .NET. What I wanted to do was
  1. Build on windows using Microsoft .NET as per usual
  2. Build using mono on windows
  3. Build using mono on linux
  4. Use nuget package restore on all three
Getting this all working was not terribly difficult but I did have to do a fair amount of googling. Here is what I needed to do to hopefully this will save someone some time.

Installing the latest version of mono
Windows:
  1. Download the 3.x from http://www.go-mono.com/mono-downloads/download.html
  2. Create dmcs.bat in C:\Program Files (x86)\Mono-3.0.10\bin as this is missing in the latest download
    1. See https://bugzilla.xamarin.com/show_bug.cgi?id=8813
    2. REM dmcs.bat compatibility shim for mcs
      @echo off
      call mcs -sdk:4 %*
Linux:
  1. See http://www.meebey.net/posts/mono_3.0_preview_debian_ubuntu_packages/

  2. Add this line to your /etc/apt/sources.list file:
       deb http://debian.meebey.net/experimental/mono /

  3. apt-get update
  4. apt-get install mono-complete




Creating a mono solution and projects

Mono’s xbuild is not yet 100% compatible with msbuild. MonoDevelop is also not 100% compatible with the VS 2012 solution/project format. So to make my life easier I’ve written a simple C# script that generates mono solutions and projects from the VS2012 ones.

This is pretty simple and works really well. It also means I can easily have separate output folders for the windows and mono binaries.

Get the source from my gist at https://gist.github.com/andrevdm/5655285#file-updateprojectfileversion-cs




Getting NuGet & package restore working on linux
  1. Import the required certificates
    1. See http://stackoverflow.com/questions/15181888/nuget-on-linux-error-getting-response-stream/16589218#comment24184791_16589218
    2. sudo mozroots --import --machine --sync
    3. sudo certmgr -ssl -m https://go.microsoft.com
    4. sudo certmgr -ssl -m https://nugetgallery.blob.core.windows.net
    5. sudo certmgr -ssl -m https://nuget.org

  2. Create a mono specific NuGet.target

      1. See http://nuget.codeplex.com/SourceControl/changeset/view/0b1e224884a3#src/Build/NuGet.targets

      2. Or use my version (minor modifications) that works with the project generator above
        https://gist.github.com/andrevdm/5660800#file-nuget-mono-targets

There is also some great info on NuGet here

  1. http://www.lextm.com/2013/01/how-to-use-nuget-on-mono-part-i.html
  2. http://www.lextm.com/2013/01/how-to-use-nuget-on-mono-part-ii.html
  3. http://www.lextm.com/2013/02/debugging-on-mono-xbuild-issue.html





Build scripts

Finally to wrap it all up here are build scripts for linux and windows


Linux
#!/bin/bash
export EnableNuGetPackageRestore=true
mono ./makeMonoProjectsAndSln.exe MySolution.sln
xbuild /p:TargetFrameworkProfile="" MySolution.mono.sln




Windows
@echo off

makeMonoProjectsAndSln.exe MySolution.sln

"C:\Program Files (x86)\Mono-3.0.10\bin\xbuild.bat" /p:TargetFrameworkProfile="" MySolution.mono.sln

Friday, 29 March 2013

Efficiently Tracking Response Time Percentiles (in C#)

 

When looking for a better way to track response times than a simple min/max/average statistic recently I found a great article that had a clever solution. This article shows how to efficiently track the n-th percentile performance while storing only a small amount of data. See the full original article here http://techblog.molindo.at/2009/11/efficiently-tracking-response-time-percentiles.html

The original code is in Java but I needed it in .NET so I’ve created a .net version on github (https://github.com/andrevdm/PercentilePerformance). I chose to do a complete rewrite rather than porting the Java code so the class names etc will be different. The idea however is the same.

My .net version can generate output in three formats

PNG

clip_image002

HTML

image

 

Text

image

 

I hope this proves useful to someone.

Monday, 25 February 2013

Learning AngularJs

 

I recently had to build a simple HTML application and decided to use AngularJS. I’ve used KnockOut in the past and found it easy to use. AngularJS is a little more opinionated than KO so there is a bit more that needs to be done to get a basic app working. However it is still simple and easy to follow and the end result definitely justifies the tiny bit of extra work.

Where I did have a problem was in understanding how the change tracking works. In KnockOut it is very clear, observables do all of the work and observables are easy to understand. In AngularJS there are no observables and everything works like “magic”. This so far has been my biggest issue with AngularJS. I find it hard to simply follow a set of rules without any understanding of the reasoning behind them. When I started building a slightly more complicated application it refused to work correctly and I could not work out why with the “magic” explanation.

After a little bit of searching I was able to come up with an explanation of how it worked and based on that some guidelines for structuring my app. The end result was very impressive. The code was simple, I had separated concerns and everything just worked. Overall I’ll definitely be using AngularJS more.

 

Pushing back the magic

Firstly AngularJS uses dirty tracking rather than observables. It will periodically scan you scope variables to see if their values have changed from the previous scan and if they have it will then updated the UI and fire the change events. That is it, pretty simple actually.

The other thing that greatly simplified my application was to use broadcast messages rather than trying to share things across the $rootScope. This allowed me to have controllers that are completely separate. Interaction between the controllers is always event-based. This also avoids complexities that arise when you are going across scopes and having to check what phase angular is in

 

Example

As a simple example I’ll show how I structured a simple tabbed interface. As this is not a post about angular binding but rather about the JS structure I’ve just bound directly to JSON text

This is what the UI looks like. There are two buttons that represent the tab pages and an area for the tab content.

image

 

Here is overall structure. Red arrows show the controllers responsible for each section of the view. Green arrows show the message broadcasting.

 

image

 

The code for the HTML page is straightforward

<!doctype html>
<html ng-app="PerformanceApp">
<head>
<script src="angular.min.js"></script>
<script src="PerformanceApp.js"></script>
<script src="NodePerformanceCtrl.js"></script>
<script src="NodesCtrl.js"></script>

<link href="cluster.css" rel="stylesheet" type="text/css" />

<title>Cluster overview</title>
</head>
<body>
<div class="tabs">
<button ng-click="CurrentTab='Nodes'" ng-class="{'selTab': CurrentTab=='Nodes', 'unSelTab': CurrentTab!='Nodes'}">Nodes</button>
<button ng-click="CurrentTab='NodePerformance'" ng-class="{'selTab': CurrentTab=='NodePerformance', 'unSelTab': CurrentTab!='NodePerformance'}">Performance</button>
</div>

<div class="tab" ng-controller="NodesCtrl" ng-show="CurrentTab=='Nodes'">
<div class="tabHeader">Nodes</div>
<span class="tabBody">
<pre>{{Nodes|json}}</pre>
</span>
</div>

<div class="tab" ng-controller="NodePerformanceCtrl" ng-show="CurrentTab=='NodePerformance'">
<div class="tabHeader">Performance</div>
<span class="tabBody">
<pre>{{Performance|json}}</pre>
</span>
</div>

</body>
</html>


 



The “tab” buttons show or hide sections by setting the value of the CurrentTab scope variable. The “tabs” are just divs each with its own controller.



This is the application initialisation code



var app = angular.module('PerformanceApp', []);

app.run( function( $timeout, $http, $rootScope ){
$rootScope.CurrentTab = "Nodes";

var machines = [
{"Name": "m1", "IP": "127.0.0.1"},
{"Name": "m2", "IP": "127.0.0.2"}
];

$timeout(
function(){
$rootScope.$broadcast( 'machinesUpdated', machines );
},
500 );

} );


Again nice and simple. On app.run




  1. the default tab is set


  2. A dummy list of machines is created. In the real app this is fetched using ajax


  3. A broadcast message is schedule in 500ms



 



The controllers then respond to the broadcast and update their local scope variables



function NodePerformanceCtrl($scope,$http,$timeout) {
$scope.Performance = {};

$scope.$on( "machinesUpdated", function( event, args ){
for( var m in args ){
var machine = args[m];

$scope.Performance[machine.Name] = machine.IP;
}

} )
}


 



Though this is a trivial example it does show how AngularJS helps you layout your application. It should also illustrate how using $broadcast messages help keep your controllers separated.

Sunday, 8 January 2012

WPF Layered Drawing


This post demonstrates a simple way to draw in WPF using multiple layers. The layered drawing classes are less than 100 lines in total and fairly simple. Below I’ll describe the demo app, layered drawing and then how the code for the layered drawing works.

 

Retained mode drawing

Drawing in WPF is very different from drawing in windows forms. Drawing in windows forms is done in immediate mode, drawing in WPF is done in retained mode. What this means is that in WPF once you have drawn a visual that visual knows how to redraw itself. You don’t need to redraw it every time some part of the display changes, WPF does it for you. You should not be doing your drawing in OnRender, the WPF equivalent of OnDraw, rather you should be drawing visuals that are then only redrawn when required.

As a practical example of how this makes things easier consider an application that draws graphics in multiple layers. In the application shown below there are multiple layers; one for the text, one for the background etc.

image

Scrolling moves the text up/down

image

Since each element is drawn in a separate layer, to move the the text down all you do is redraw the text layer. All the other layers remain unchanged and thus don’t need to be redrawn manually.

 

 

Drawing on the layers

The layered drawing classes presented here make it easy to create a UI like this. Here is an example of creating a layer

1: m_layers.AddLayer( 10, DrawBackground, ChangeType.Resize );

Here a layer is created. Its priority (discussed later) is set to 10. DrawBackground is the method responsible for drawing the layer being registered. Resize is the ChangeType that will cause the layer to be redrawn.

Here is the DrawBackground method

private void DrawBackground( DrawingContext ctx ) 
{
var pen = new Pen( Brushes.Black, 1 );
var rect = new Rect( 0, 0, m_layers.ActualWidth, m_layers.ActualHeight );
ctx.DrawRoundedRectangle( Brushes.Black, pen, rect, 50, 50 );


Now that that is in place having the layer redrawn when the window resized is easy



protected override void OnRenderSizeChanged( SizeChangedInfo sizeInfo )
{
base.OnRenderSizeChanged( sizeInfo );

Draw( ChangeType.Resize );
}


What you need to do is call the Draw method with the appropriate ChangeType, here ChangeType.Resize.



The layer registration and change notification scheme allows you to decouple the drawing logic from the events that cause changes to the UI. So should you later want to add another layer that is also redrawn when the window is resized, then you just add a new layer registration. The code in the OnRenderSizeChanged method does not change at all. In a real application you would use this separation to keep the events and drawing logic separate (model vs view or separate layers managed by different classes)



To complete the discussion of the demo application here is the full layer registration



private void OnLoaded( object sender, RoutedEventArgs e )
{
m_layers.AddLayer( 10, DrawBackground, ChangeType.Resize );
m_layers.AddLayer( 11, DrawBackgroundBlock );

m_layers.AddLayer( 20, DrawStaticForeground );
m_layers.AddLayer( 21, DrawText, ChangeType.Scroll );

m_layers.AddLayer( 30, DrawForeground );


And here is the OnScroll handler.



private void OnScroll( object sender, ScrollEventArgs e )
{
Draw( ChangeType.Scroll );
}



And that is it. Using layers like this is pretty simple and it is very efficient as is uses DrawingVisuals. Drawing in this manner can be used for many purposes, for example to build a text editor control. You could have a layer for the text, one for the gutters & margins and one for the selection highlight.



The source code for the demo app is attached. Hopefully you will find this method useful.



Below is a description of how the layered drawing is implemented.





Implementation



The ChangeType enum is used to describe different types of changes. The exact values used would depend on your application.



[Flags]
public enum ChangeType
{
Redraw = 1,
Resize = 2,
Scroll = 4,
}



The WpfLayerInfo class stores the details for each layer.



public class WpfLayerInfo
{
public WpfLayerInfo( int priority, Action<DrawingContext> draw, DrawingVisual visual, ChangeType notifyOnChange )
{
NotifyOnChange = notifyOnChange;
Priority = priority;
Visual = visual;
Draw = draw;
}

public ChangeType NotifyOnChange { get; private set; }
public int Priority { get; private set; }
public DrawingVisual Visual { get; private set; }
public Action<DrawingContext> Draw { get; private set; }
}



Layers in WPF



Building the layers in WPF is relatively strait forward. Each layer is a DrawingVisual and the layers are contained in a FrameworkElement user control. You then override the GetVisualChild() method to return a layer’s visual.



public class WpfLayers : FrameworkElement
{
private readonly VisualCollection m_children;
private readonly List<WpfLayerInfo> m_layers = new List<WpfLayerInfo>();

public WpfLayers()
{
m_children = new VisualCollection( this );
}

public void AddLayer( ... )
{
var drawingVisual = new DrawingVisual();

...

m_children.Add( l.Visual );
}

protected override int VisualChildrenCount
{
get { return m_children.Count; }
}

protected override Visual GetVisualChild( int index )
{
if( index < 0 || index >= m_children.Count )
{
throw new ArgumentOutOfRangeException( "index" );
}

return m_children[index];
}
}



The code above illustrates the main points, there is a FrameworkElement with a VisualCollection (m_children) containing DrawingVisuals. Each DrawingVisual represents a layer. m_layers is a list of WpfLayerInfo objects each describing a layer.



Adding a layer is handled by the AddLayer method



public void AddLayer( int priority, Action<DrawingContext> draw, ChangeType notifyOnChange = ChangeType.Redraw )
{
var drawingVisual = new DrawingVisual();

var layerInfo = new WpfLayerInfo( priority, draw, drawingVisual, notifyOnChange );
m_layers.Add( layerInfo );

//Sort the layers by priority
m_layers.Sort( ( x, y ) => x.Priority.CompareTo( y.Priority ) );

//Remove all the visual layers and add them in order
m_children.Clear();
m_layers.ForEach( l => m_children.Add( l.Visual ) );
}



This method creates a new DrawingVisual and a WpfLayerInfo for the new layer. The visuals are then added to the VisualCollection in order of priority. I.e lowest priority at the bottom of the Z-order.



The Draw method which controls what layers will be redrawn



public void Draw( ChangeType change )
{
var affected = from l in m_layers
where ((change & ChangeType.Redraw) != 0) || ((l.NotifyOnChange & change) != 0)
orderby l.Priority
select l;

foreach( WpfLayerInfo layer in affected )
{
DrawingContext ctx = layer.Visual.RenderOpen();
layer.Draw( ctx );
ctx.Close();
}
}



This method first gets the layers that need to be redrawn (lines 3 to 6) ordered by priority. ChangeType.Redraw is treated as a special case, if it is selected then all layers are selected (i.e. to be redrawn)



Next for each selected layer a DrawingContext is created and passed to the layer’s draw method.



The Demo



The XAML for the demo looks like this



<Window x:Class="LayeredDrawingDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:LayeredDrawingDemo="clr-namespace:LayeredDrawingDemo"
Title="Layered Drawing"
Loaded="OnLoaded"
Height="350"
Width="500">
<DockPanel LastChildFill="true">
<TextBlock Name="m_log" DockPanel.Dock="Right" Width="150" Margin="5"/>
<ScrollBar Name="m_scroll" DockPanel.Dock="Right" Scroll="OnScroll" />
<LayeredDrawingDemo:WpfLayers x:Name="m_layers" DockPanel.Dock="Left"></LayeredDrawingDemo:WpfLayers>
</DockPanel>
</Window>


The layers are added on line 12.



As shown above the OnLoad handler creates the layers and redraws all layers



private void OnLoaded( object sender, RoutedEventArgs e )
{
m_layers.AddLayer( 10, DrawBackground, ChangeType.Resize );
m_layers.AddLayer( 11, DrawBackgroundBlock );

m_layers.AddLayer( 20, DrawStaticForeground );
m_layers.AddLayer( 21, DrawText, ChangeType.Scroll );

m_layers.AddLayer( 30, DrawForeground );

Draw( ChangeType.Redraw );
}


The window resize handler which causes the DrawBackground method to be called (ChangeType.Resize).


protected override void OnRenderSizeChanged( SizeChangedInfo sizeInfo )
{
base.OnRenderSizeChanged( sizeInfo );

m_scroll.Minimum = 0;
m_scroll.Maximum = m_layers.ActualHeight - 70;
Draw( ChangeType.Resize );
}




The scroll handler



private void OnScroll( object sender, ScrollEventArgs e )
{
Draw( ChangeType.Scroll );
}


The Draw() method



private void Draw( ChangeType change )
{
m_layers.Draw( change );
}



One of he draw methods



private void DrawForeground( DrawingContext ctx )
{
var pen = new Pen( Brushes.Black, 1 );
var rect = new Rect( 20, 20, 50, 55 );
ctx.DrawRectangle( Brushes.Red, pen, rect );

Log( "foreground" );
}


Notice that each of the draw methods in this example log that they have been called. This makes it easy to see from the demo UI which layers are being changes. E.g. when you resize the window you will see that the text is not redrawn etc.



The source code for the example is available on github or as a zip . Hopefully you will find this method of drawing in WPF as useful as I have.

Sunday, 6 November 2011

Building a simple FTP server in F#

 

Why build a FTP server

I’ve just started learning F# and the application I decided to build needs a way of exposing a read-only directory structure/file system. I initially looked at WebDAV but it seemed unnecessarily complex for what I was trying to do, there also is apparently a compatibility issue between the windows implementation and the standard. FTP on the other hand is well documented, well supported and cross platform.

As it turns out building a FTP server that supports the minimum number of features is actually pretty simple. By implementing only ten of the many possible FTP commands I was able to build a FTP server that windows explorer and a number of FTP clients could happily use.

I was very surprised how easy building the server was. I’m sure I’ll use this approach for a number of different applications in the future. Hopefully I can convince you to do the same :)

Two things to note however; firstly this is obviously not meant to be a production grade server but it could certainly be taken to that extent if required. Secondly this is only my third day of F# so I may well have missed some F# tricks or done some things in a non-idiomatic way.

The FTP Protocol

FTP is a line based protocol like telnet. This is part of what makes implementing it so easy.

For example this is what an authentication conversation would look like

Client: [Connect to server]

 
 

Server: [220 Hello, welcome to …]

Client: USER usr123

 
 

Server: 331 password required

Client: PASS abcde

Server: 230 logged in

That is it, pretty simple, right?

For more details on the protocol you can take a look at RFC959 (http://www.ietf.org/rfc/rfc959.txt).

There are also many sites that explain the protocol in plain English. Here are three sites that I found particularly useful in getting started

  1. An Overview of the File Transfer Protocol - http://www.ncftp.com/libncftp/doc/ftp_overview.html
  2. List of raw FTP commands - http://www.nsftools.com/tips/RawFTP.htm
  3. FTP, File Transfer Protocol - http://www.networksorcery.com/enp/protocol/ftp.htm

The minimal set of FTP commands

To get the FTP server to support a few FTP clients (FileZilla, explorer and ftp.exe command line client) I had to implement the following commands

  • USER - User name
  • PASS - Password
  • CWD - Change working directory
  • PWD - Print working directory
  • TYPE - Binary/text mode. I just ignored this command
  • LIST/NLST - Print a directory listing
  • PORT - Set the data port for an active data transfer
  • RETR - Retrieve a file
  • QUIT - Quit

Clearly there is a lot that I have not implemented and I may extend what I support (e.g. CDUP, PASSV etc) but for now this is all I need.

Code structure

The full source code is available on githib at https://github.com/andrevdm/FSharpFtpServer.

The code is structured as follows

  • SocketExtensions – contains extension methods for the Socket class. This was copied from http://fssnip.net/1E
  • SocketServer - The main server. This accepts new connections and creates a new ISocketHandler derived class to handle the requests.
  • LineProtocolHandler - Implements ISocketHandler. Reads data off the socket and calls the abstract Handle method after a line is read. NB The way I’m reading one byte at a time is far from optimal but it is simple and works well enough for now.
  • FtpHandler - inherits from LineProtocolHandler and implements the Handle method to handle each command line as it is received.
  • IDirectoryProvider. Interface for classes exposing a directory. I.e. responsible for generating the directory listing, keeping track of the current directory and downloading files etc.
  • FileSystemDirectoryProvider - a directory provider for exposing a real file system. (This still needs work).

The idea here is that it is easy to plug in different functionality, for example different directory providers. I’m using this server to expose a virtual file system (something like the Git file system, more about that in a future blog) so I’ve not put much effort into the FilySystemDirectoryProvider but it should be pretty simple to get it working correctly.

 

Code examples

The login conversation was show above this is how it looks in the code.

When a client connects the server sends a 220 “hello” command.

do! t.Send 220 "Hello" socket

Here Send is a method that takes the code (220), the sting (“Hello”) and the socket to respond to.

The logged in state is then managed by the loginState mutable state variable. This can have one of the following values

type ftpLoginState = 
| ExpectUserName
| ExpectPassword
| LoggedIn



 



The incoming lines are sent to the Handle() method




override t.Handle( line, socket ) = 
async{
if line = "QUIT" then
t.Stop()
else
match loginState with
| ExpectUserName -> do! t.HandleLoginUserName( line, socket )
| ExpectPassword -> do! t.HandleLoginPassword( line, socket )
| LoggedIn -> do! t.HandleCommand( line, socket )
| _ -> failwith ("unknown ftpLoginState " + loginState.ToString())
}



 



This method works as follows




  1. If the QUIT command is received then call the Stop() method to terminate the connection


  2. All other commands are then interpreted based on the current login state

    1. If expecting a user name call HandleLoginUserName


    2. If expecting a password call HandleLoginPassword


    3. If logged in the call the HandleCommand method which handles the main FTP commands


    4. Any other state is invalid





 



The HandleCommand method then responds to the rest of the FTP commands.



member t.HandleCommand( line, socket ) = 
async{
let c,r = t.SplitCmd line

match c with
| "PORT" -> do! t.SetPort( r, socket )
| "NLST"
| "LIST" -> do! t.SendList( r, socket )
| "PWD" -> do! t.Send 257 ("\"" + dirProvider.CurrentPath + "\" is the current directory") socket
| "TYPE" -> do! t.Send 200 "ignored" socket
| "RETR" -> do! t.RetrieveFile( r, socket )
| "CWD" ->
if dirProvider.ChangeDir( r ) then do! t.Send 200 "directory changed" socket
else do! t.Send 552 "Invalid directory" socket
| _ -> do! t.Send 502 "Command not implemented" socket

}


 



The SplitCmd call is a simple method to split the received line.




member t.SplitCmd( line ) =

  let m = Regex.Match( line, @"^(?<cmd>[^ ]+)( (?<rest>.*))?" )


  if not m.Success then failwith ("invalid command: " + line)


  (m.Groups.["cmd"].Value, m.Groups.["rest"].Value)




 



LIST / NLST



The LIST and NLST commands request the server to send a directory listing. Rather bizarrely there is no actual standard for this format. However most FTP server return the listing matching the standard unix ls format and most FTP clients expect this too.



Here is how the FileSystemDirectoryProvider returns the files and sub-directories of the current path



member t.List() = 
let dir = new StringBuilder()

let info = new DirectoryInfo( physicalDirectory )

info.GetFiles()
|> Array.iter (fun f ->
dir.AppendFormat( "-r--r--r-- 1 owner group {1} 1970 01 01 {0}", f.Name, f.Length ).AppendLine() |> ignore )

info.GetDirectories()
|> Array.iter (fun d ->
dir.AppendFormat( "dr--r--r-- 1 owner group {1} 1970 01 01 {0}", d.Name, 0 ).AppendLine() |> ignore )

dir.ToString()


 



This listing is then sent back to the client by the FtpHandler, see the section on the PORT command below




member t.SendList( p, socket ) = 
async{
do! t.Send 150 "Opening ASCII mode data connection for /bin/ls" socket

use sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
let endpoint = IPEndPoint(ipAddr, port)
sender.Connect( endpoint )

let! sent = sender.AsyncSend( Encoding.ASCII.GetBytes( dirProvider.List() ) )
do! t.Send 226 "Listing completed." socket
}



 



PORT and active mode data transfer



FTP uses different ports for its command and data communications. The command socket is always on the port that you connect on (typically port 21), data ports are created dynamically as required.



There are two ways in which ports are assigned




  1. In active mode the client creates a socket to listen for data on and tells the server the IP and port number


  2. In passive mode the client requests that server create a listener and return the IP and port. Passive mode is often preferred as it is simpler to support behind a firewall.



It was marginally simpler for me to implement active mode so for now that is all the server supports.



In active mode a data transfer like the LIST command described above would look like this







































Client: PORT 127,0,0,1,4,1  
  Server: 200 PORT command successful
Client: LIST  
  Server: 150 Opening ASCII mode data connection for /bin/ls
  Server: [Data sent to 127.0.0.1:1026]
  Server: 226 Listing completed


 



So the client creates a listening socket and sends the details to the server. The port is split into high,low. The number = high * 256 + low. In this case 4*256+1 = 1026



The client then requests the list.



Finally the server then




  1. Tells the client that it is about to send the data


  2. Sends the data over the new data connection


  3. Tells the client that the data was sent successfully



 



In summary



I was able to build a simple FTP server in a few hundred lines of F#. I’m sure I’ll be using this code in a number of projects in the future. I hope that it will prove useful to you as well.



 









Learning F#



These are the resource that I’ve found particularly useful in learning F#.



F# Snipits - http://fssnip.net - There are some fantastic sample here. My base server code is based on http://fssnip.net/1E



Expert F# - http://www.amazon.com/Expert-F-Experts-Voice-NET/dp/1590598504 - A brilliant F# book.

Sunday, 11 September 2011

TmMq - Trivial MongoDB Message Queue

I've just pushed a very simple message queue system that used MongoDB as the data store. I've found this useful for testing message queuing and projects where I dont want to deploy a full blown message queuing system.

Hopefully it will help someone else too.

You can get the source and binaries from github
             https://github.com/andrevdm/TrivialMongoMessageQueue


Below is the readme from the project
----------------------------------------

TmMq

TmMq - Trivial MongoDB Message Queue is a very simple .net message queuing system built on MongoDB
It is not in any way meant to compete with any of the fully fledged messaging solutions (Hortet, ActiveMQ etc) but it is a nice, lightweight alternative that has proved useful to me.

Features

  1. No TmMq server
  2. Send & receive
  3. Publish / subscribe
  4. Redeliver on error with limit on retry
  5. Limit on delivery (at-least-once delivery)
  6. Message expiry
  7. Message holding (only deliver in future)
  8. Errors logged in message
  9. Dynamic properties collection
  10. Synchronous and asynchronous receive
  11. Written in C#

 

TODO

  1. Triggers based on tailable MongoDB cursor. I'm not sure this is necessary, I will implement it if I find I need it.
  2. More unit tests

 

Licence

FreeBSD License. See licence.txt

 

Usage

See the unit tests for examples of all the features including pub/sub, retry, errors etc.

 

Send & receive

using( var send = new TmMqSender( "TestSendBeforeReceiveStarted" ) )
{
     var msg = new TmMqMessage();
     msg.Text = "msg1";
     send.Send( msg );
}

using( var recv = new TmMqReceiver( "TestSendBeforeReceiveStarted" ) )
{
     ITmMqMessage recieved = recv.Receive().FirstOrDefault();
}

 

Pub/sub

using( var rcvr1 = new TmMqPubSubReceiver( "TestPubSub" ) )
using( var rcvr2 = new TmMqPubSubReceiver( "TestPubSub" ) )
using( var rcvr3 = new TmMqPubSubReceiver( "TestPubSub" ) )
using( var rcvr4 = new TmMqPubSubReceiver( "TestPubSub" ) )
{
     var r1 = new List();
     var r2 = new List();
     var r3 = new List();
     var r4 = new List();

     rcvr1.StartReceiving( 1, r1.Add );
     rcvr2.StartReceiving( 1, r2.Add );
     rcvr3.StartReceiving( 1, r3.Add );
     rcvr4.StartReceiving( 1, r4.Add );

     using( var sender = new TmMqPubSubSender( "TestPubSub" ) )
     {
            var msg = new TmMqMessage();
            msg.Text = "ps-" + i;
            sender.Send( msg );
     }

Thursday, 16 December 2010

Parameterised queries–don’t use AddWithValue

I’ve just had another run in with the SQL query optimiser. Here is my tale of woe.
I had a very simple parameterised query. Something like this
select * from People where ID10 = @idnumber

However when I looked at the SQL execution plan it looked like this
ex1
The thing to notice here is that it is doing an index scan. This made no sense to me since the ID10 column is indexed and so I should be seeing an index seek.

Using SQL profiler confirmed that this query was taking nearly half a second on our production server, which was way too slow.

This is the query as recorded by SQL profiler after being executed by the C# code
exec sp_executesql N'select * from People where ID10=@id', N'@id nvarchar(10)', N'1001010001'

And here is the table
image

What was strange is that when I executed the SQL without a parameter
  exec sp_executesql N'select id10 from People where ID10=''1001010001'''

I got this execution plan
ex2

An index seek, exactly what I wanted. This query took between 1 and 10ms, so more than 400 times faster!

After much searching I finally found the answer;

This parameterised query works perfectly, it uses an index seek
exec sp_executesql N'select id10 from People where ID10=@id', N'@id varchar(10)', '1001010001'

The difference? One letter… This query passes the ID number as a varchar not an nvarchar. Since the index is on an varchar, passing in a nvarchar means that there will be an index scan not a seek. I have no idea why SQL does not first convert to a varchar and then do a scan, but it does not…

The culprit in the C# code was this line
cmd.Parameters.AddWithValue( "id", idNumber )

The AddWithValue forces .net to infer the type you are passing in and since all strings in .net are unicode the parameter is sent as an nvarchar.

Know this, the fix was trivial
cmd.Parameters.Add( "id", SqlDbType.VarChar, 10 ).Value = idNumber,

Here the type and length are specified explicitly so the query is correct and SQL uses an index scan.

So in summary don’t use AddWithValue