Wednesday 1 January 2014

RandomNumberGenerator in C#

To generate random numbers in C#, it is possible to use the class RandomNumberGenerator in System.Security.Cryptography namespace in .NET. This class can be easier to use with a simple wrapper class. The wrapper class provided here returns either an integer or an unsigned integer. The "randomness" is better in this class than in the default Random generator of .NET, the Random class. This class will for example emit the same random values for two instances instantiated at almost the same time of the Random class. The wrapper class looks like this:

 public static class RandomGenerator
    {

        private static readonly RandomNumberGenerator generator;

        static RandomGenerator()
        {
            generator = RandomNumberGenerator.Create();
        }

        public static int GetNext()
        {
            byte[] rndArray = new byte[4];
            generator.GetBytes(rndArray);
            return BitConverter.ToInt32(rndArray, 0);
        }

        public static uint GetNextUnsigned()
        {
            byte[] rndArray = new byte[4];
            generator.GetBytes(rndArray);
            return BitConverter.ToUInt32(rndArray, 0);
        }



    }

The class is in fact a static class with a static RandomNumberGenerator instance created in the static constructor. The methods to create a new random number uses the GetBytes method to fill a four byte array. We could of course generate longer arrays and create for example 64-bits integers, but here just a four byte array is used. Either an integer or unsigned integer is returned by the two respective methods for this. I have not bothered to refactor this simple class. The BitConverter class converts the byte array to int or unsigned int (32-bits) starting at index 0. We could also return other datatypes here than just integers. Simple unit test:

 [TestFixture]
    public class UnitTest1
    {

        [Test]
        public void GetNextInteger()
        {
            int random = RandomGenerator.GetNext();
            Debug.WriteLine(random);
        }

        [Test]
        public void GetNextUInteger()
        {
            uint random = RandomGenerator.GetNextUnsigned();
            Debug.WriteLine(random);
        }

    }

Sample output:

------ Test started: Assembly: TestRandomNumberGeneratorTest.dll ------

-1821995826

1013025195

2 passed, 0 failed, 0 skipped, took 0,42 seconds (NUnit 2.6.2).


If you would like random numbers in a specified range, for example 0 to 99, you could take the integer and do a modulo 100 operation, e.g RandomGenerator.GetNextUnsigned() % 100. Of course, this is tied to the desired range you want. If a range between for example -20 and 20 is desired, you could for example do something like: -20 + (RandomGenerator.GetNextUnsigned() % 41). The bottom line is that you should not entrust the randomness of System.Random class but use the RandomNumberGenerator class in System.Security.Cryptography if you want to generate random integers, signed or unsigned that exhibit more distributed randomness than the pseudorandomness of System.Random.

Thursday 24 October 2013

Using Snoop and PowerShell to interrogate View Models in WPF applications

It is possible to use Snoop to interrogate View Models in WPF applications. If you first install Snoop, check that you run Snoop as an administrator, if you cannot attach to the process which is your WPF application. Start snooping the application, then move to the tab Powershell. Use Ctrl+Shift and click on the visual or ui element you want to inspect in the GUI. You will see a pink border around the ui element or visual and this will then be possible to inspect further. Go to the PowerShell tab and start interrogating the object. In the MVVM WPF application at my work, we can see the view model in the property DataContext.ViewModel. It is possible to further drill down to properties in the ViewModel quite easily. Example follows, I have selected a RadGridView in my application and select the Visual property, then look at the DataContext of the Visual, drill down further to the ModelCollection property, which in this particular example is a property of the data context object of which the selected visual is data bound to. This object contains a property of type ObservableCollection which has got some custom object inside. The collection object is then piped to the Select operator in Powershell and this Select operator projects the properties of each object in the ModelCollection, in this particular case I select OperationId, OperatingDate and OperationStatus. This is then further piped to Format-Table which is used with the argument -autoresize. The resulting selector is then:

$selected.Visual.DataContext.ModelCollection | Select OperationId, OperatingDate, OperationStatus | Format-Table -autosize

OperationId OperatingDate       OperationStatus
----------- -------------       ---------------
       2076                              Urgent
         70                              Urgent
       2162 23.10.2013 00:00:00       Operation
       2165 23.10.2013 00:00:00       Operation
       2196 23.10.2013 00:00:00       Operation
       2197 23.10.2013 00:00:00       Operation
          0 23.10.2013 00:00:00            None
          0 23.10.2013 00:00:00            None
          0 23.10.2013 00:00:00            None
          0 23.10.2013 00:00:00            None
          0 23.10.2013 00:00:00            None
          0 23.10.2013 00:00:00            None
          0 23.10.2013 00:00:00            None
          0 23.10.2013 00:00:00            None
          0 23.10.2013 00:00:00            None
          0 23.10.2013 00:00:00            None
          0 23.10.2013 00:00:00            None
       1913                              Urgent
       2192 23.10.2013 00:00:00       Operation
       2193 23.10.2013 00:00:00       Operation
       2194 23.10.2013 00:00:00       Operation
       2013 23.10.2013 00:00:00       Operation
       2195 23.10.2013 00:00:00       Operation
       2161 23.10.2013 00:00:00       Operation


It could be possible to pipe this further to the Export-Csv Powershell cmdlet and you can have Excel launch the resulting .csv file. This shows how SnoopWpf can be used to do powerful runtime analysis and inspection of WPF applications and also support Powershell operators. Both technical testers and WPF developers will find this useful. To get started, install Snoop Wpf created by the brilliant developer Cory Plotts and can be downloaded from here: Snoop WPF

Friday 26 July 2013

Creating a simple autocomplete control with Bootstrap for with a remote JSON service

I have worked a bit with the Twitter Bootstrap javascript library / framework and testet out the TypeAhead control. I could not find a complete example of how to get the autocomplete items from a remote JSON service, so I testet it out myself. Let's first define a web service (ASP.NET) which will return the list of sovereign states in the world:
//using System;
//using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;

namespace TestBootstrapCss
{
    /// <summary>
    /// Summary description for CountryService
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    [System.Web.Script.Services.ScriptService]
    public class CountryService : System.Web.Services.WebService
    {

        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public Country[] GetCountries(string query)
        {
            if (cachedCountryList == null)
                cachedCountryList = GetCountryList();

            var result = cachedCountryList.Where(c => c.Name.StartsWith(query, System.StringComparison.CurrentCultureIgnoreCase)).ToArray();
            return result;
        }

        public class Country
        {
            public int Id { get; set; }

            public string Name { get; set; }

            public int Population { get; set; }

            public double WorldPercentage { get; set; }

        }

        private static Country[] cachedCountryList = null; 

        public Country[] GetCountryList()
        {
            return new Country[] {
                new Country { Id =1,Name = "China",Population = 1354040000 ,WorldPercentage = 19.07 },
                new Country { Id =2,Name = "India",Population = 1210569573 ,WorldPercentage = 17.05 },
                new Country { Id =3,Name = "United States",Population = 316318000 ,WorldPercentage = 4.45 },
                new Country { Id =4,Name = "Indonesia",Population = 237641326 ,WorldPercentage = 3.35 },
                new Country { Id =5,Name = "Brazil",Population = 193946886 ,WorldPercentage = 2.73 },
                new Country { Id =6,Name = "Pakistan",Population = 183766000 ,WorldPercentage = 2.59 },
                new Country { Id =7,Name = "Nigeria",Population = 173615000 ,WorldPercentage = 2.45 },
                new Country { Id =8,Name = "Bangladesh",Population = 152518015 ,WorldPercentage = 2.15 },
                new Country { Id =9,Name = "Russia",Population = 143400000 ,WorldPercentage = 2.02 },
                new Country { Id =10,Name = "Japan",Population = 127350000 ,WorldPercentage = 1.79 },
                new Country { Id =11,Name = "Mexico",Population = 118419000 ,WorldPercentage = 1.67 },
                new Country { Id =12,Name = "Philippines",Population = 98100000 ,WorldPercentage = 1.38 },
                new Country { Id =13,Name = "Vietnam",Population = 88780000 ,WorldPercentage = 1.25 },
                new Country { Id =14,Name = "Ethiopia",Population = 86613986 ,WorldPercentage = 1.22 },
                new Country { Id =15,Name = "Egypt",Population = 83661000 ,WorldPercentage = 1.18 },
                new Country { Id =16,Name = "Germany",Population = 80493000 ,WorldPercentage = 1.13 },
                new Country { Id =17,Name = "Iran",Population = 76768000 ,WorldPercentage = 1.08 },
                new Country { Id =18,Name = "Turkey",Population = 75627384 ,WorldPercentage = 1.07 },
                new Country { Id =19,Name = "Democratic Republic of the Congo",Population = 67514000 ,WorldPercentage = 0.95 },
                new Country { Id =20,Name = "Thailand",Population = 65926261 ,WorldPercentage = 0.93 },
                new Country { Id =21,Name = "France[9]",Population = 65684000 ,WorldPercentage = 0.92 },
                new Country { Id =22,Name = "United Kingdom",Population = 63181775 ,WorldPercentage = 0.89 },
                new Country { Id =23,Name = "Italy",Population = 59704082 ,WorldPercentage = 0.84 },
                new Country { Id =24,Name = "Myanmar",Population = 53259000 ,WorldPercentage = 0.75 },
                new Country { Id =25,Name = "South Africa",Population = 52981991 ,WorldPercentage = 0.75 },
                new Country { Id =26,Name = "South Korea",Population = 50219669 ,WorldPercentage = 0.71 },
                new Country { Id =27,Name = "Colombia",Population = 47159000 ,WorldPercentage = 0.66 },
                new Country { Id =28,Name = "Spain",Population = 47059533 ,WorldPercentage = 0.66 },
                new Country { Id =29,Name = "Ukraine",Population = 45495252 ,WorldPercentage = 0.64 },
                new Country { Id =30,Name = "Tanzania",Population = 44928923 ,WorldPercentage = 0.63 },
                new Country { Id =31,Name = "Kenya",Population = 44354000 ,WorldPercentage = 0.62 },
                new Country { Id =32,Name = "Argentina",Population = 40117096 ,WorldPercentage = 0.57 },
                new Country { Id =33,Name = "Poland",Population = 38533299 ,WorldPercentage = 0.54 },
                new Country { Id =34,Name = "Sudan",Population = 37964000 ,WorldPercentage = 0.53 },
                new Country { Id =35,Name = "Algeria",Population = 37900000 ,WorldPercentage = 0.53 },
                new Country { Id =36,Name = "Canada",Population = 35141542 ,WorldPercentage = 0.49 },
                new Country { Id =37,Name = "Uganda",Population = 34131400 ,WorldPercentage = 0.48 },
                new Country { Id =38,Name = "Iraq",Population = 33330000 ,WorldPercentage = 0.47 },
                new Country { Id =39,Name = "Morocco",Population = 32973200 ,WorldPercentage = 0.46 },
                new Country { Id =40,Name = "Peru",Population = 30475144 ,WorldPercentage = 0.43 },
                new Country { Id =41,Name = "Malaysia",Population = 29747000 ,WorldPercentage = 0.42 },
                new Country { Id =42,Name = "Uzbekistan",Population = 29559100 ,WorldPercentage = 0.42 },
                new Country { Id =43,Name = "Saudi Arabia",Population = 29195895 ,WorldPercentage = 0.41 },
                new Country { Id =44,Name = "Venezuela",Population = 28946101 ,WorldPercentage = 0.41 },
                new Country { Id =45,Name = "Nepal",Population = 26494504 ,WorldPercentage = 0.37 },
                new Country { Id =46,Name = "Afghanistan",Population = 25500100 ,WorldPercentage = 0.36 },
                new Country { Id =47,Name = "North Korea",Population = 24895000 ,WorldPercentage = 0.35 },
                new Country { Id =48,Name = "Ghana",Population = 24658823 ,WorldPercentage = 0.35 },
                new Country { Id =49,Name = "Yemen",Population = 24527000 ,WorldPercentage = 0.35 },
                new Country { Id =50,Name = "Mozambique",Population = 24366112 ,WorldPercentage = 0.34 },
                new Country { Id =51,Name = "Taiwan[10]",Population = 23340136 ,WorldPercentage = 0.33 },
                new Country { Id =52,Name = "Ivory Coast",Population = 23202000 ,WorldPercentage = 0.33 },
                new Country { Id =53,Name = "Australia",Population = 23096296 ,WorldPercentage = 0.33 },
                new Country { Id =54,Name = "Syria",Population = 21377000 ,WorldPercentage = 0.3 },
                new Country { Id =55,Name = "Madagascar",Population = 20696070 ,WorldPercentage = 0.29 },
                new Country { Id =56,Name = "Angola",Population = 20609294 ,WorldPercentage = 0.29 },
                new Country { Id =57,Name = "Cameroon",Population = 20386799 ,WorldPercentage = 0.29 },
                new Country { Id =58,Name = "Sri Lanka",Population = 20277597 ,WorldPercentage = 0.29 },
                new Country { Id =59,Name = "Romania",Population = 20121641 ,WorldPercentage = 0.28 },
                new Country { Id =60,Name = "Burkina Faso",Population = 17322796 ,WorldPercentage = 0.24 },
                new Country { Id =61,Name = "Niger",Population = 17129076 ,WorldPercentage = 0.24 },
                new Country { Id =62,Name = "Kazakhstan",Population = 17010000 ,WorldPercentage = 0.24 },
                new Country { Id =63,Name = "Netherlands",Population = 16793700 ,WorldPercentage = 0.24 },
                new Country { Id =64,Name = "Chile",Population = 16634603 ,WorldPercentage = 0.23 },
                new Country { Id =65,Name = "Ecuador",Population = 15535800 ,WorldPercentage = 0.22 },
                new Country { Id =66,Name = "Guatemala",Population = 15438384 ,WorldPercentage = 0.22 },
                new Country { Id =67,Name = "Mali",Population = 15302000 ,WorldPercentage = 0.22 },
                new Country { Id =68,Name = "Cambodia",Population = 15135000 ,WorldPercentage = 0.21 },
                new Country { Id =69,Name = "Malawi",Population = 14388600 ,WorldPercentage = 0.2 },
                new Country { Id =70,Name = "Senegal",Population = 13567338 ,WorldPercentage = 0.19 },
                new Country { Id =71,Name = "Zambia",Population = 13092666 ,WorldPercentage = 0.18 },
                new Country { Id =72,Name = "Zimbabwe",Population = 12973808 ,WorldPercentage = 0.18 },
                new Country { Id =73,Name = "Chad",Population = 12825000 ,WorldPercentage = 0.18 },
                new Country { Id =74,Name = "South Sudan",Population = 11296000 ,WorldPercentage = 0.16 },
                new Country { Id =75,Name = "Cuba",Population = 11163934 ,WorldPercentage = 0.16 },
                new Country { Id =76,Name = "Belgium",Population = 11156136 ,WorldPercentage = 0.16 },
                new Country { Id =77,Name = "Guinea",Population = 10824200 ,WorldPercentage = 0.15 },
                new Country { Id =78,Name = "Greece",Population = 10815197 ,WorldPercentage = 0.15 },
                new Country { Id =79,Name = "Tunisia",Population = 10777500 ,WorldPercentage = 0.15 },
                new Country { Id =80,Name = "Portugal",Population = 10562178 ,WorldPercentage = 0.15 },
                new Country { Id =81,Name = "Rwanda",Population = 10537222 ,WorldPercentage = 0.15 },
                new Country { Id =82,Name = "Czech Republic",Population = 10512800 ,WorldPercentage = 0.15 },
                new Country { Id =83,Name = "Somalia[11]",Population = 10496000 ,WorldPercentage = 0.15 },
                new Country { Id =84,Name = "Haiti",Population = 10413211 ,WorldPercentage = 0.15 },
                new Country { Id =85,Name = "Bolivia",Population = 10389913 ,WorldPercentage = 0.15 },
                new Country { Id =86,Name = "Benin",Population = 10323000 ,WorldPercentage = 0.15 },
                new Country { Id =87,Name = "Burundi",Population = 10163000 ,WorldPercentage = 0.14 },
                new Country { Id =88,Name = "Hungary",Population = 9906000 ,WorldPercentage = 0.14 },
                new Country { Id =89,Name = "Sweden",Population = 9588569 ,WorldPercentage = 0.14 },
                new Country { Id =90,Name = "Belarus",Population = 9458700 ,WorldPercentage = 0.13 },
                new Country { Id =91,Name = "Dominican Republic",Population = 9445281 ,WorldPercentage = 0.13 },
                new Country { Id =92,Name = "Azerbaijan",Population = 9235100 ,WorldPercentage = 0.13 },
                new Country { Id =93,Name = "Austria",Population = 8464554 ,WorldPercentage = 0.12 },
                new Country { Id =94,Name = "Honduras",Population = 8385072 ,WorldPercentage = 0.12 },
                new Country { Id =95,Name = "United Arab Emirates",Population = 8264070 ,WorldPercentage = 0.12 },
                new Country { Id =96,Name = "Switzerland",Population = 8058100 ,WorldPercentage = 0.11 },
                new Country { Id =97,Name = "Israel",Population = 8034900 ,WorldPercentage = 0.11 },
                new Country { Id =98,Name = "Tajikistan",Population = 8000000 ,WorldPercentage = 0.11 },
                new Country { Id =99,Name = "Bulgaria",Population = 7282041 ,WorldPercentage = 0.1 },
                new Country { Id =100,Name = "Serbia[12]",Population = 7241295 ,WorldPercentage = 0.1 },
                new Country { Id =101,Name = "Hong Kong (China)",Population = 7173900 ,WorldPercentage = 0.1 },
                new Country { Id =102,Name = "Papua New Guinea",Population = 7059653 ,WorldPercentage = 0.099 },
                new Country { Id =103,Name = "Paraguay",Population = 6672631 ,WorldPercentage = 0.094 },
                new Country { Id =104,Name = "Laos",Population = 6580800 ,WorldPercentage = 0.093 },
                new Country { Id =105,Name = "Jordan",Population = 6467500 ,WorldPercentage = 0.09 },
                new Country { Id =106,Name = "Eritrea",Population = 6333000 ,WorldPercentage = 0.089 },
                new Country { Id =107,Name = "Libya",Population = 6202000 ,WorldPercentage = 0.087 },
                new Country { Id =108,Name = "Togo",Population = 6191155 ,WorldPercentage = 0.087 },
                new Country { Id =109,Name = "El Salvador",Population = 6183000 ,WorldPercentage = 0.087 },
                new Country { Id =110,Name = "Sierra Leone",Population = 6092000 ,WorldPercentage = 0.086 },
                new Country { Id =111,Name = "Nicaragua",Population = 6071045 ,WorldPercentage = 0.086 },
                new Country { Id =112,Name = "Denmark",Population = 5605836 ,WorldPercentage = 0.079 },
                new Country { Id =113,Name = "Kyrgyzstan",Population = 5551900 ,WorldPercentage = 0.078 },
                new Country { Id =114,Name = "Finland",Population = 5434357 ,WorldPercentage = 0.077 },
                new Country { Id =115,Name = "Slovakia",Population = 5410728 ,WorldPercentage = 0.076 },
                new Country { Id =116,Name = "Singapore",Population = 5312400 ,WorldPercentage = 0.075 },
                new Country { Id =117,Name = "Turkmenistan",Population = 5240000 ,WorldPercentage = 0.074 },
                new Country { Id =118,Name = "Norway",Population = 5063709 ,WorldPercentage = 0.071 },
                new Country { Id =119,Name = "Lebanon",Population = 4822000 ,WorldPercentage = 0.068 },
                new Country { Id =120,Name = "Costa Rica",Population = 4667096 ,WorldPercentage = 0.066 },
                new Country { Id =121,Name = "Central African Republic",Population = 4616000 ,WorldPercentage = 0.065 },
                new Country { Id =122,Name = "Ireland",Population = 4585400 ,WorldPercentage = 0.065 },
                new Country { Id =123,Name = "Georgia[13]",Population = 4483800 ,WorldPercentage = 0.063 },
                new Country { Id =124,Name = "New Zealand",Population = 4471380 ,WorldPercentage = 0.063 },
                new Country { Id =125,Name = "Republic of the Congo",Population = 4448000 ,WorldPercentage = 0.063 },
                new Country { Id =126,Name = "Palestine[14]",Population = 4420549 ,WorldPercentage = 0.062 },
                new Country { Id =127,Name = "Liberia",Population = 4294000 ,WorldPercentage = 0.06 },
                new Country { Id =128,Name = "Croatia",Population = 4290612 ,WorldPercentage = 0.06 },
                new Country { Id =129,Name = "Bosnia and Herzegovina",Population = 3839737 ,WorldPercentage = 0.054 },
                new Country { Id =130,Name = "Oman",Population = 3831553 ,WorldPercentage = 0.054 },
                new Country { Id =131,Name = "Puerto Rico (USA)",Population = 3667084 ,WorldPercentage = 0.052 },
                new Country { Id =132,Name = "Kuwait",Population = 3582054 ,WorldPercentage = 0.05 },
                new Country { Id =133,Name = "Moldova[15]",Population = 3559500 ,WorldPercentage = 0.05 },
                new Country { Id =134,Name = "Mauritania",Population = 3461041 ,WorldPercentage = 0.049 },
                new Country { Id =135,Name = "Panama",Population = 3405813 ,WorldPercentage = 0.048 },
                new Country { Id =136,Name = "Uruguay",Population = 3286314 ,WorldPercentage = 0.046 },
                new Country { Id =137,Name = "Armenia",Population = 3031200 ,WorldPercentage = 0.043 },
                new Country { Id =138,Name = "Lithuania",Population = 2960733 ,WorldPercentage = 0.042 },
                new Country { Id =139,Name = "Albania",Population = 2821977 ,WorldPercentage = 0.04 },
                new Country { Id =140,Name = "Mongolia",Population = 2754685 ,WorldPercentage = 0.039 },
                new Country { Id =141,Name = "Jamaica",Population = 2711476 ,WorldPercentage = 0.038 },
                new Country { Id =142,Name = "Namibia",Population = 2113077 ,WorldPercentage = 0.03 },
                new Country { Id =143,Name = "Lesotho",Population = 2074000 ,WorldPercentage = 0.029 },
                new Country { Id =144,Name = "Slovenia",Population = 2060461 ,WorldPercentage = 0.029 },
                new Country { Id =145,Name = "Macedonia",Population = 2059794 ,WorldPercentage = 0.029 },
                new Country { Id =146,Name = "Botswana",Population = 2024904 ,WorldPercentage = 0.029 },
                new Country { Id =147,Name = "Latvia",Population = 2013400 ,WorldPercentage = 0.028 },
                new Country { Id =148,Name = "Qatar",Population = 1963124 ,WorldPercentage = 0.028 },
                new Country { Id =149,Name = "Gambia",Population = 1849000 ,WorldPercentage = 0.026 },
                new Country { Id =150,Name = "Guinea-Bissau",Population = 1704000 ,WorldPercentage = 0.024 },
                new Country { Id =151,Name = "Gabon",Population = 1672000 ,WorldPercentage = 0.024 },
                new Country { Id =152,Name = "Equatorial Guinea",Population = 1622000 ,WorldPercentage = 0.023 },
                new Country { Id =153,Name = "Trinidad and Tobago",Population = 1328019 ,WorldPercentage = 0.019 },
                new Country { Id =154,Name = "Estonia",Population = 1286540 ,WorldPercentage = 0.018 },
                new Country { Id =155,Name = "Mauritius",Population = 1257900 ,WorldPercentage = 0.018 },
                new Country { Id =156,Name = "Swaziland",Population = 1250000 ,WorldPercentage = 0.018 },
                new Country { Id =157,Name = "Bahrain",Population = 1234571 ,WorldPercentage = 0.017 },
                new Country { Id =158,Name = "Timor-Leste",Population = 1066409 ,WorldPercentage = 0.015 },
                new Country { Id =159,Name = "Djibouti",Population = 864618 ,WorldPercentage = 0.012 },
                new Country { Id =160,Name = "Cyprus[16]",Population = 862 ,WorldPercentage = 0.012 },
                new Country { Id =161,Name = "Fiji",Population = 858038 ,WorldPercentage = 0.012 },
                new Country { Id =162,Name = "Réunion (France)",Population = 821136 ,WorldPercentage = 0.012 },
                new Country { Id =163,Name = "Guyana",Population = 784894 ,WorldPercentage = 0.011 },
                new Country { Id =164,Name = "Bhutan",Population = 73674 ,WorldPercentage = 0.01 },
                new Country { Id =165,Name = "Comoros",Population = 7243 ,WorldPercentage = 0.01 },
                new Country { Id =166,Name = "Montenegro",Population = 620029 ,WorldPercentage = 0.0087 },
                new Country { Id =167,Name = "Macau (China)",Population = 582 ,WorldPercentage = 0.0082 },
                new Country { Id =168,Name = "Western Sahara[17]",Population = 567 ,WorldPercentage = 0.008 },
                new Country { Id =169,Name = "Solomon Islands",Population = 561 ,WorldPercentage = 0.0079 },
                new Country { Id =170,Name = "Luxembourg",Population = 537 ,WorldPercentage = 0.0076 },
                new Country { Id =171,Name = "Suri,Name",Population = 534189 ,WorldPercentage = 0.0075 },
                new Country { Id =172,Name = "Cape Verde",Population = 491875 ,WorldPercentage = 0.0069 },
                new Country { Id =173,Name = "Malta",Population = 416055 ,WorldPercentage = 0.0059 },
                new Country { Id =174,Name = "Guadeloupe (France)",Population = 403355 ,WorldPercentage = 0.0057 },
                new Country { Id =175,Name = "Martinique (France)",Population = 394173 ,WorldPercentage = 0.0056 },
                new Country { Id =176,Name = "Brunei",Population = 393162 ,WorldPercentage = 0.0055 },
                new Country { Id =177,Name = "Bahamas",Population = 351461 ,WorldPercentage = 0.0049 },
                new Country { Id =178,Name = "Iceland",Population = 32381 ,WorldPercentage = 0.0045 },
                new Country { Id =179,Name = "Maldives",Population = 31728 ,WorldPercentage = 0.0045 },
                new Country { Id =180,Name = "Belize",Population = 312971 ,WorldPercentage = 0.0044 },
                new Country { Id =181,Name = "Barbados",Population = 2742 ,WorldPercentage = 0.0039 },
                new Country { Id =182,Name = "French Polynesia (France)",Population = 26827 ,WorldPercentage = 0.0038 },
                new Country { Id =183,Name = "Vanuatu",Population = 258213 ,WorldPercentage = 0.0036 },
                new Country { Id =184,Name = "New Caledonia (France)",Population = 255651 ,WorldPercentage = 0.0036 },
                new Country { Id =185,Name = "French Guiana (France)",Population = 22904 ,WorldPercentage = 0.0032 },
                new Country { Id =186,Name = "Mayotte (France)",Population = 2126 ,WorldPercentage = 0.003 },
                new Country { Id =187,Name = "Samoa",Population = 18782 ,WorldPercentage = 0.0026 },
                new Country { Id =188,Name = "São Tomé and Príncipe",Population = 187356 ,WorldPercentage = 0.0026 },
                new Country { Id =189,Name = "Saint Lucia",Population = 166526 ,WorldPercentage = 0.0023 },
                new Country { Id =190,Name = "Guam (USA)",Population = 159358 ,WorldPercentage = 0.0022 },
                new Country { Id =191,Name = "Curaçao (Netherlands)",Population = 150563 ,WorldPercentage = 0.0021 },
                new Country { Id =192,Name = "Saint Vincent and the Grenadines",Population = 109 ,WorldPercentage = 0.0015 },
                new Country { Id =193,Name = "United States Virgin Islands (USA)",Population = 106405 ,WorldPercentage = 0.0015 },
                new Country { Id =194,Name = "Kiribati",Population = 104573 ,WorldPercentage = 0.0015 },
                new Country { Id =195,Name = "Grenada",Population = 103328 ,WorldPercentage = 0.0015 },
                new Country { Id =196,Name = "Tonga",Population = 103036 ,WorldPercentage = 0.0015 },
                new Country { Id =197,Name = "Federated States of Micronesia",Population = 101823 ,WorldPercentage = 0.0014 },
                new Country { Id =198,Name = "Aruba (Netherlands)",Population = 101484 ,WorldPercentage = 0.0014 },
                new Country { Id =199,Name = "Jersey (UK)",Population = 97857 ,WorldPercentage = 0.0014 },
                new Country { Id =200,Name = "Seychelles",Population = 90945 ,WorldPercentage = 0.0013 },
                new Country { Id =201,Name = "Antigua and Barbuda",Population = 86295 ,WorldPercentage = 0.0012 },
                new Country { Id =202,Name = "Isle of Man (UK)",Population = 84497 ,WorldPercentage = 0.0012 },
                new Country { Id =203,Name = "Andorra",Population = 76246 ,WorldPercentage = 0.0011 },
                new Country { Id =204,Name = "Dominica",Population = 71293 ,WorldPercentage = 0.001 },
                new Country { Id =205,Name = "Bermuda (UK)",Population = 64237 ,WorldPercentage = 0.0009 },
                new Country { Id =206,Name = "Guernsey (UK)",Population = 62431 ,WorldPercentage = 0.00088 },
                new Country { Id =207,Name = "Greenland (Denmark)",Population = 5637 ,WorldPercentage = 0.00079 },
                new Country { Id =208,Name = "Marshall Islands",Population = 55548 ,WorldPercentage = 0.00078 },
                new Country { Id =209,Name = "American Samoa (USA)",Population = 55519 ,WorldPercentage = 0.00078 },
                new Country { Id =210,Name = "Cayman Islands (UK)",Population = 55456 ,WorldPercentage = 0.00078 },
                new Country { Id =211,Name = "Saint Kitts and Nevis",Population = 54 ,WorldPercentage = 0.00076 },
                new Country { Id =212,Name = "Northern Mariana Islands (USA)",Population = 53883 ,WorldPercentage = 0.00076 },
                new Country { Id =213,Name = "Faroe Islands (Denmark)",Population = 48244 ,WorldPercentage = 0.00068 },
                new Country { Id =214,Name = "Sint Maarten (Netherlands)",Population = 37429 ,WorldPercentage = 0.00053 },
                new Country { Id =215,Name = "Saint Martin (France)",Population = 36979 ,WorldPercentage = 0.00052 },
                new Country { Id =216,Name = "Liechtenstein",Population = 36842 ,WorldPercentage = 0.00052 },
                new Country { Id =217,Name = "Monaco",Population = 36136 ,WorldPercentage = 0.00051 },
                new Country { Id =218,Name = "San Marino",Population = 32382 ,WorldPercentage = 0.00046 },
                new Country { Id =219,Name = "Turks and Caicos Islands (UK)",Population = 31458 ,WorldPercentage = 0.00044 },
                new Country { Id =220,Name = "Gibraltar (UK)",Population = 29752 ,WorldPercentage = 0.00042 },
                new Country { Id =221,Name = "British Virgin Islands (UK)",Population = 29537 ,WorldPercentage = 0.00042 },
                new Country { Id =222,Name = "Åland Islands (Finland)",Population = 28502 ,WorldPercentage = 0.0004 },
                new Country { Id =223,Name = "Caribbean Netherlands (Netherlands)",Population = 21133 ,WorldPercentage = 0.0003 },
                new Country { Id =224,Name = "Palau",Population = 2077 ,WorldPercentage = 0.00029 },
                new Country { Id =225,Name = "Cook Islands (NZ)",Population = 14974 ,WorldPercentage = 0.00021 },
                new Country { Id =226,Name = "Anguilla (UK)",Population = 13452 ,WorldPercentage = 0.00019 },
                new Country { Id =227,Name = "Wallis and Futuna (France)",Population = 13152 ,WorldPercentage = 0.00019 },
                new Country { Id =228,Name = "Tuvalu",Population = 11264 ,WorldPercentage = 0.00016 },
                new Country { Id =229,Name = "Nauru",Population = 9945 ,WorldPercentage = 0.00014 },
                new Country { Id =230,Name = "Saint Barthélemy (France)",Population = 8938 ,WorldPercentage = 0.00013 },
                new Country { Id =231,Name = "Saint Pierre and Miquelon (France)",Population = 6081 ,WorldPercentage = 0.00006 },
                new Country { Id =232,Name = "Montserrat (UK)",Population = 4922 ,WorldPercentage = 0.00005 },
                new Country { Id =233,Name = "Saint Helena Ascension and Tristan da Cunha (UK)",Population = 4 ,WorldPercentage = 0.00004 },
                new Country { Id =234,Name = "Svalbard and Jan Mayen (Norway)",Population = 2655 ,WorldPercentage = 0.00003 },
                new Country { Id =235,Name = "Falkland Islands (UK)",Population = 2563 ,WorldPercentage = 0.00003 },
                new Country { Id =236,Name = "Norfolk Island (Australia)",Population = 2302 ,WorldPercentage = 0.00002 },
                new Country { Id =237,Name = "Christmas Island (Australia)",Population = 2072 ,WorldPercentage = 0.00002 },
                new Country { Id =238,Name = "Niue (NZ)",Population = 1613 ,WorldPercentage = 0.00002 },
                new Country { Id =239,Name = "Tokelau (NZ)",Population = 1411 ,WorldPercentage = 0.00001 },
                new Country { Id =240,Name = " Vatican City",Population = 800 ,WorldPercentage = 0.00001 },
                new Country { Id =241,Name = "Cocos (Keeling) Islands (Australia)",Population = 550 ,WorldPercentage = 0.000001 },
                new Country { Id =242,Name = "Pitcairn Islands (UK)",Population = 66 ,WorldPercentage = 0.0000000 }
            };

        }

    }

}

As you can see, we must tag the service with the ScriptService and tag the WebMethod with the ScriptMethod attribute, specifying the JSON responseformat. We also need to add some to our web.config:

<?xml version="1.0"?>

<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->

<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />

    <webServices>
      <protocols>
        <add name="HttpGet" />
        <add name="HttpPost"/>
      </protocols>
    </webServices>

  </system.web>

</configuration>


We also need some GUI here to test out the TypeAhead control:


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head<
    <title></title>
    <link href="Content/bootstrap.css" rel="stylesheet" />
    <link href="Content/bootstrap-responsive.css" rel="stylesheet" />
</head>
<body>

    <div class="row">

    <div class="span12">
    <input type="text" id="tbCountries" /> 
   

    </div class="row">
   
    <script src="Scripts/jquery-2.0.3.js"></script>
    <script src="Scripts/bootstrap.js"></script>
    <script src="Scripts/underscore.js"></script>

    <script type="text/javascript">

        $(function () {
         

            var countries;

            $("#tbCountries").typeahead({
                source: function (query, process) {
                    return $.ajax({
                        type: "POST",
                        url: 'http://localhost:52523/CountryService.asmx/GetCountries',
                        data: JSON.stringify({query: query }),
                        contentType: "application/json; charset=utf-8",
                        dataType: "json",
                        success:
                        function (data) {
                            countries = data.d; 
                            var countryIds = _.map(countries, function(c){
                                return c.Id; 
                            }); 
                            return process(countryIds);
                        }
                    });
                },
                matcher: function (item) {
                    return true;
                },
                sorter: function (items) {
                    return items;
                },
                highlighter: function (id) {
                    var country = _.find(countries, function (c) {
                        return c.Id == id;
                    });
                    return country.Name + " Population: " + country.Population; 
                },
                updater: function (id) {
                    var country = _.find(countries, function (c) {
                        return c.Id == id;
                    });
                    return country.Name;
                }
            });

        });

    </script>
</body>
</html>


To sum up, to make the TypeAhead control work in my example, I had to implement stub implementations of matcher, sorter, highlighter (must be implemented such that the custom Country object instances return in JSON object is visible, this is a display template in other words) and updater (will update the text field with the autocomplete / TypeAhead feature). Source also sets a global variable countries here for simplicity, and continues processing the ids, you can see that we use Underscore.Js here for the array processing. The highlighter and updater method uses the find method of Underscore.js to find the relevant country. The end result is a functioning auto complete example for the Bootstrap TypeAhead control that uses a remote JSON service. I am not sure why the data.d variable was returned from the service. I did not specify "data.d" anywhere in my code, but this is where I could find the returned JSON data. It is not very elegant to set the countries to a global variable, we could of course encapsulate this better using a "provider" to encapsulate the data for encapsulation and consistency protection. But the key point of this article was to help others getting started with the TypeAhead control in Bootstrap with remote JSON calls returning objects with properties and not just simple string arrays. I find the Bootstrap documentation from Twitter as good, but not exemplary. It is sometimes hard to find good programming examples on the different controls. The end result is an autocomplete control that looks nice and can display compound data: