Xander.PasswordValidator – WordListRegExBuilder

When word lists are processed a regular expression is built in order to quickly traverse the lists. The regular expression is built using a number of builders which create various parts of the regular expression. One for checking the password itself, and another for testing the password against the list but modified by adding a numeric suffix. You can add your own by creating your own class derived from WordListRegExBuilder and then adding it to the WordListProcessOptions.

The WordListRegExBuilder is an abstract base class and demands that the GetRegularExpression method is implemented in any concrete derived class. It also has a method called RegExEncode which takes a string and encodes it for use in a regular expression, escaping out all the special symbols used by the regular expression engine.

For example, say you want to validate the password against the list, but check also for a numeric prefix you can create a class to build that part of the regular expression. That class would look something like this:

using Xander.PasswordValidator;
namespace Xander.Demo.PasswordValidator.Web.Mvc3.Helpers
{
  public class NumericPrefixBuilder : WordListRegExBuilder
  {
    public override string GetRegularExpression(string password)
    {
      return "[0-9]" + RegExEncode(password);
    }
  }
}

And to use this in the validator, add it to the settings like this:

var settings = new PasswordValidationSettings();
settings.WordListProcessOptions.CustomBuilders.Add(typeof(NumericPrefixBuilder));

The Validator will create a new instance of your class and run the GetRegularExpression method. It will then incorporate that in to the regular expression that it is building and test word lists using it.

Xander.PasswordValidatator – Validation Handlers

If the password validator does not have the validation rules that you need for your project then it is easily extendable. You can create your own ValidationHander derived classes and set add them via the PasswordValdiationSettings class.

ValidationHandler

The ValidationHandler class is an abstract base class which is extended in the Xander.PasswordValidator framework itself to provide the various built in validation routines. (You can see examples of some of them here on GitHub)

You can create your own by simply creating a class and setting Xander.PasswordValidator.ValidationHandler as the base class and overriding the Validate() method.

The Validate method simply accepts the password as the parameter and returns a Boolean. Return true to indicate that the password passes the validation, false if it fails the validation.

For example, here is a very simple validator that rejects passwords that look like dates:

using System;
using Xander.PasswordValidator;

namespace Demo.ValidationHandlers
{
  public class NoDatesValidationHandler : ValidationHandler
  {
    public override bool Validate(string password)
    {
      DateTime date;
      var parseResult = DateTime.TryParse(password, out date);
      return !parseResult;
    }
  }
}

To set this up so that the validator calls it, it needs to be added as part of the settings. You pass in the type of the handler. The Validation framework will create an instance of the handler for you, if it needs it. If validation fails before it gets a chance to run your validator then your validator will not run.

var settings = new PasswordValidationSettings();
settings.CustomValidators.Add(typeof(NoDatesValidationHandler));

CustomValidationHandler<TData>

This derives from ValidationHandler and is used when you need to pass some additional data or objects into your validation handler for it to work properly.

The Validate method works as before, except you now have access to an additional property from the base class that contains your custom data, called CustomData. CustomData is the object passed in through the settings.

To pass in the data through the settings you use the CustomSettings property on the PasswordValidationSettings class. For example:

settings = new PasswordValidationSettings();
settings.MinimumPasswordLength = 6;
settings.CustomValidators.Add(typeof(PasswordHistoryValidationHandler));
settings.CustomSettings.Add(typeof(PasswordHistoryValidationHandler), new Repository());

The key passed into CustomSettings is a type that refers to the ValidationHandler type that the settings are to be sent to.

The ValidationHandler looks something like this:

using System.Linq;
using System.Web;
using Xander.PasswordValidator;

namespace Demo.ValidationHandlers
{
  public class PasswordHistoryValidationHandler : CustomValidationHandler
  {
    public override bool Validate(string password)
    {
      var user = HttpContext.Current.User;
      var history = CustomData.GetPasswordHistory(user.Identity.Name);
      return !history.Any(h => string.Compare(password, h, true) == 0);
    }
  }
}

In the above example, the settings pass in a repository which is passed on to the ValidationHandler when the Validator is run. The repository is used to get a history of passwords (It is a dummy repository in this example – In real life you should never have access to the plain text passwords like this) and the history can be checked against the current password to ensure that it does not match any of the historical passwords.

There is a slightly updated set of assemblies for this as I made some changes to way the CustomValidationHandler works: PasswordValidator.0.2.0.0.zip

Xander.PasswordValidator – The config file

Earlier in this series I introduced the config file, but I didn’t say much about it other that show an example. In this post I’ll go in to more detail.

Defining the config section

To define the section:

<configSections>
<!-- Set up other config sections here—>
   <sectionGroup name="passwordValidation">
      <section name="rules" type="Xander.PasswordValidator.Config.PasswordValidationSection, Xander.PasswordValidator, Version=0.1.0.0, Culture=neutral, PublicKeyToken=fe72000dffcf195f" allowLocation="true" allowDefinition="Everywhere"/>
   </sectionGroup> </configSections>

This defines the configuration section will will appear later in the config file.

An example of the config section itself:

<!-- The configuration section that describes the configuration for the password validation -->
<passwordValidation>
   <rules minimumPasswordLength="6" needsNumber="false" needsLetter="false" needsSymbol="false">
     <wordListProcessOptions checkForNumberSuffix="true" checkForDoubledUpWord="true" checkForReversedWord="true" />
     <standardWordLists>
       <add value="FemaleNames"/>
       <add value="MaleNames"/>
       <add value="MostCommon500Passwords"/>
       <add value="Surnames"/>
     </standardWordLists>
     <customWordLists>
       <add file="WordLists/MyCustomWordList.txt" />
       <add file="WordLists/MyOtherCustomWordList.txt" />
     </customWordLists>
   </rules> </passwordValidation>

The rules

The rules section defines the actual rules by which the passwords will be validated.

<rules minimumPasswordLength="13" needsNumber="true" needsLetter="true" needsSymbol="true">
  • minimumPasswordLength: a positive integer that defines the minimum number of characters needed for a valid password. It is optional and if missing will default to 8.
  • needsNumber: Boolean that indicates whether the password needs a number in it. It is optional and if missing will default to true.
  • needsLetter: Boolean that indicates whether the password needs a letter in it. It is optional and if missing will default to true.
  • needsSymbol: Boolean that indicates whether the password needs a symbol in it. It is optional and if missing will default to false.

Rules can have a number of child elements also.

  • wordListProcessOptions: A set of options for how the word lists are processed
  • standardWordLists: A collection of built in word lists to use to check the password against.
  • customWordLists: A collection of custom word lists to use to check the password against.

The word list process options

By default, checking the password against the word lists only checks to see if the password is in a word list. These are additional options for checking against the word lists.

<wordListProcessOptions checkForNumberSuffix="true" checkForDoubledUpWord="true" checkForReversedWord="true" />
  • checkForNumberSuffix: Indicates whether the password should be checked to see if it is simply in the word list with an additional digit appended. This is optional, and by default is false.
  • checkForDoubledUpWord: Indicates whether the password should be checked to see if it is the same sequence repeated over again, and if it is to see if the first half is in the word list. This is optional and the default value is false.
  • checkForReversedWord: Indicates the a reversed form of the password should be checked to see if it in the word list. This is optional and the default value is false.

Standard word lists

This element is a container for a collection of standard word list items.

     <standardwordlists>
       <add value="FemaleNames" />
       <add value="MaleNames" />
       <add value="MostCommon500Passwords" />
       <add value="Surnames" />
     </standardwordlists>

The valid words list are:

Custom word lists

This element is a container for a collection of file paths to plain text files that contain custom word lists to check against. A word list file is simply a plain text file with one word per line.

     <customWordLists>
       <add file="WordLists/MyCustomWordList.txt" />
       <add file="WordLists/MyOtherCustomWordList.txt" />
     </customWordLists>

The paths are relative to the working directory of the application in which the password validator is operating. In an ASP.NET web application the paths should be prefixed with the ~ to ensure they are correctly mapped on the server relative to the root of the web application.

Xander.PasswordValidator – In a Web Application

In the last post I introduced Xander.PasswordValidator and showed the basics of how to configure it. In this post I’m going to show the PasswordValidationAttribute and how you can use it in your ASP.NET MVC application.

PasswordValidation attribute

At its simplest, all you need to do is to decorate a property in your model with the PasswordValidationAttribute, like this:

  public class SomeModel
  {
     [PasswordValidation]
     public string Password { get; set; }






   
    // Other stuff goes here
  }

That will validate the password based on the settings in the config file, which I discussed briefly in my previous post, and I’ll go into more detail later.

Registering the Password Validator

In order for the file paths to custom word lists to be resolved correctly in a web application you need to register the validator in the Application_Start() method in your web application’s HttpApplication derived class. (Or anywhere before first use).

For example, the Application_Start() method may look like this:

protected void Application_Start()
{
   PasswordValidatorRegistration.Register(); // Register password validator
   AreaRegistration.RegisterAllAreas();
   RegisterGlobalFilters(GlobalFilters.Filters);
   RegisterRoutes(RouteTable.Routes); }

Validating settings from code

As the settings can get quite complex they cannot be set directly in the attribute that you use to decorate the model. Instead they can be set elsewhere and referenced in the attribute.

The settings can be configured as normal then added to the PasswordValidationSettingsCache. For example:

var settings = new PasswordValidationSettings();
settings.NeedsNumber = true;
settings.NeedsSymbol = true;
settings.MinimumPasswordLength = 6;
settings.StandardWordLists.Add(StandardWordList.FemaleNames);
settings.StandardWordLists.Add(StandardWordList.MaleNames);
settings.StandardWordLists.Add(StandardWordList.Surnames);
settings.StandardWordLists.Add(StandardWordList.MostCommon500Passwords);
PasswordValidationSettingsCache.Add("StandardRules", settings);

This code would typically be placed in the Application_Start() method, after registering the password validator.

The important line is the last one. It adds the setting tot he cache with the name “StandardRules”. That can then be references in the attribute later. Like this:

public class MyModel
{
  [PasswordValidation("StandardRules")]
  public string Password { get; set; } 
}

The PasswordValidationAttribute references the entry in the cache, which is then retrieved to perform the validation.

Xander.PasswordValidator – A Simple Demonstration

I recently introduced the Xander.PasswordValidator project I’m working on in a previous blog post. In this post I intend to demonstrate some of the basics of how to use it.

Validator

At the most core is the Validator class. It performs the validation of the password and returns a value to the caller to let them know if the validation passed or failed.

The validator can take settings set by the caller, or it can find settings in the application’s configuration file.

Here is a simple example of it working:

var settings = new PasswordValidationSettings();
settings.MinimumPasswordLength = 6;
settings.NeedsLetter = true;
settings.NeedsNumber = true;
settings.StandardWordLists.Add(StandardWordList.MostCommon500Passwords);
var validator = new Validator(settings);
bool result = validator.Validate("MySuperSecretPassword");

First off, a settings class is created, then various options are set. If you don’t set any options then the validator allows any password.

In this example the settings mandate the a password must be at least 6 characters, it must have a letter and it must have a number, and it must not appear in the built in list of the most common 500 passwords.

Then the Validator is created and passed the settings that we’ve prepared.

Finally, the Validate method is called passing in the password that is to be validated. The result indicates whether the password passed or failed (in the example above, it failed as it does not contain a number).

Settings from the config file

If you prefer to have the settings for the validator in the config file then you can instantiate a Validator without passing anything to its constructor and it will use the settings in the config file instead.

It should go without saying that you should only put the settings in the config file in a secure environment.

To use settings in the config file you must set up a the section where the settings will go, and then create the section with the settings in it.

To define the section:

<configSections>
<!-- Set up other config sections here—>
   <sectionGroup name="passwordValidation">
      <section name="rules" type="Xander.PasswordValidator.Config.PasswordValidationSection, Xander.PasswordValidator, Version=0.1.0.0, Culture=neutral, PublicKeyToken=fe72000dffcf195f" allowLocation="true" allowDefinition="Everywhere"/>
   </sectionGroup> </configSections>

An example of the config section itself:

<!-- The configuration section that describes the configuration for the password validation -->
<passwordValidation>
   <rules minimumPasswordLength="6" needsNumber="false" needsLetter="false" needsSymbol="false">
     <wordListProcessOptions checkForNumberSuffix="true" checkForDoubledUpWord="true" checkForReversedWord="true" />
     <standardWordLists>
       <add value="FemaleNames"/>
       <add value="MaleNames"/>
       <add value="MostCommon500Passwords"/>
       <add value="Surnames"/>
     </standardWordLists>
     <customWordLists>
       <add file="WordLists/MyCustomWordList.txt" />
       <add file="WordLists/MyOtherCustomWordList.txt" />
     </customWordLists>
   </rules> </passwordValidation>

The above example uses most options available out of the box that can be put in the config file. It is worth noting that some options are only available from the settings in the code, such as being able to specify custom classes that handle parts of the validation.

Have a play

If you want to try this out for yourself the two assemblies are available here. I will be putting this on NuGet soon.

Xander.PasswordValidator

I was looking for a way to validate passwords for an upcoming project because we need to do that better than we are, so I was looking for some .NET library to do that. Unfortunately, Google only turned up a ton of regular expressions which is all fine an well, but it wasn’t really what I was looking for. I really wanted to be able to check against a dictionary of potential passwords and have it reject a password because it was in the list and it also had to check against the regular rules of “must has a number”, and so on.

So, I created Xander.PasswordValidator which is available on GitHub.

The idea is that you can create a Validator object which can then be used to evaluate the suitability of potential passwords. When creating the validator you can pass in settings from code, or have it read settings from a config file. You can extend the functionality, so if there is something that you want to check that I’ve not thought about you have points where you can extend that. If the lists of forbidden passwords are not suitable then you can add your own lists, if the rules for checking against those lists are not suitable, then you can add your own ways to check.

Also, if you write web applications using ASP.NET MVC then there is a really simple attribute you can apply to a property in your model to have the validator check the value.

Over the next few days I’ll be writing more documentation for the project and showing what can be done with it in a series of blog posts. The “official” documentation will be on the project’s wiki at GitHub. An initial version of the built code will also be available in the next few days. However, you can get the code from GitHub and build it yourself if you so desire.

Integrating Exceptioneer with OpenRasta

[NOTE: This post was created using OpenRasta 2.0 RC (rev 429)]

One service I’ve found to be increasingly useful is Exceptioneer by Pixel Programming. As I’m about to start a new project using OpenRasta I wanted to be able to use Exceptioneer with it in order that I can log any exceptions effectively.

For a basic 404 error it was very easy. Just following the instructions on the Exceptioneer site for the ASP.NET integration worked a treat.

However, a little more work was required for when something like a Handler in OpenRasta threw an exception that didn’t get caught. In this case I had to set up an OperationInterceptor in order to catch the exception and send it to Exceptioneer.

Here is the ExceptionInterceptor class:

class ExceptionInterceptor : OperationInterceptor
{
    readonly IDependencyResolver resolver;

    public ExceptionInterceptor(IDependencyResolver resolver)
    {
        this.resolver = resolver;
    }

    public override Func<IEnumerable<OutputMember>> RewriteOperation
        (Func<IEnumerable<OutputMember>> operationBuilder)
    {
        return () =>
        {
            IEnumerable<OutputMember> result = null;
            try
            {
                result = operationBuilder();
            }
            catch (Exception ex)
            {
                Client exceptioneerClient = new Client();
                exceptioneerClient.CurrentException = ex;
                exceptioneerClient.Submit();
                throw;
            }
            return result;
        };
    }
}

Note that you have to include using Exceptioneer.WebClient; at the top of the file.

What this gives us is the ability to log any exception that is left uncaught from the Handler, log it then allow OpenRasta to continue on as it would have normally.

All that remains is to wire this up. In the Configuration class (if you’ve used the Visual Studio 2008 project template, or what ever your IConfigurationSource class is called otherwise) the following is added to the Configure method:

ResourceSpace.Uses.CustomDependency<IOperationInterceptor,
    ExceptionInterceptor>(DependencyLifetime.Transient);

 

Now any time a handler has an uncaught exception, it will be logged and sent off to Exceptioneer.

Further reading:

My First OpenRasta Project – Part 1

On the OpenRasta Wiki there are some instructions on getting your project up and running the manual way, should you so wish. One of the new features introduced at the last beta was a Visual Studio 2008 project template, which installs as part of the binary distribution.

Once installed you can create an OpenRasta project by going to the “Visual C#” Project Types and selecting OpenRasta ASP.NET Application (3.5) from the templates on the right of the dialog.

OpenRasta: New Project

Once the project is created you’ll see that it has set the project up, added the references to the assemblies that it needs and created an initial handler, resource and views.

OpenRasta: Solution Explorer

Before continuing further a little explanation of what each of these things are is in order.

A resource is a source of information. It is referenced via a URI. This blog post is a resource, an image is a resource, an invoice is a resource. However, a resource does not imply any particular kind of representation. In terms of OpenRasta a resource is simply an object

A handler is an object that manages the interaction of the resources. In MVC parlance it would be the “C” or controller.

A view is a regular ASP.NET page that can be rendered via the WebFormsCodec. It is not compulsory to implement any views at all if you don’t need ASP.NET.

A codec is the class responsible for encoding and decoding the representation of a resource. The built in codecs are WebForms, JSON and two types of XML.

First Code

When you get started you’ll need to configure OpenRasta. It needs to know the details of the resources you want to expose and the handlers that can deal with those resources. To do that OpenRasta looks for a class in your project that implements the IConfigurationSource interface.

If you have two or more classes that implement this interface then the first one that is found will be used. As the project template already contains a Configuration class already set up and ready to go there is nothing additional to do other than set the configuration.

In the example I’m going to show, we will be rendering an invoice. So the configuration needs to look like this:

public class Configuration : IConfigurationSource
{
    public void Configure()
    {
        using (OpenRastaConfiguration.Manual)
        {
            ResourceSpace.Has.ResourcesOfType<Invoice>()
                .AtUri("/invoice")
                .HandledBy<InvoiceHandler>()
                .AsXmlDataContract();
        }
    }
}

The configuration happens through a fluent interface. The ResourceSpace is the root object where you can define the resources in your application, what handles them and how they are represented. In this case this is going to be a fairly simple example. As it is a fluent interface it does seem to be fairly self explanatory.

The Invoice class is a simple POCO DTO that represents an invoice. POCO means Plain Old CLR Object and DTO is a Data Transfer Object. In this example the Invoice just looks like this:

public class Invoice
{
    public string Reference { get; set; }
}

The InvoiceHandler class is another POCO that happens to have methods on it that are picked up by the use of conventions. If you have a method named after an HTTP verb (like GET or POST) then OpenRasta will use it to handle that verb.

In this example we are just going to return a simple Invoice object. I don’t want to complicate the example with other things at the present, so it will, in fact, always return an invoice with the same Reference property value.

public class InvoiceHandler
{
    public Invoice Get()
    {
        return new Invoice
        {
            Reference = "123-456/ABC"
        };
    }
}

As the configuration specified that the XML Data Contract codec was to be used the invoice is rendered using that codec. The output looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Invoice xmlns:i="http://www.w3.org/2001/XMLSchema-instance"          xmlns="http://schemas.datacontract.org/2004/07/MyFirstOpenRastaProject.Resources">
  <Reference>123-456/ABC
</Invoice>

Obviously at this stage it isn’t very useful. This is just a quick demonstration showing how quickly something can be set up. In coming parts I’ll be addressing other issues that so that more useful things can be done.

 

NOTE: This blog post is based on OpenRasta 2.0 Beta 2 (2.0.2069.364): [Download]

Technorati Tags:

Dynamic Objects in C# 4.0

It seems only very recently that I was posting about this wonderful new feature in C# 3.0 called LINQ and its associated language features such as anonymous types, object initialisers and lambda expressions. Soon C#4.0 will be released and it has a host of new goodies to look forward to.

So far I’ve just been dabbling with dynamic types and the dynamic keyword.

C# has been up until this point a purely statically bound language. That meant that if the compiler couldn’t find the method to bind to then it wasn’t going to compile the application. Other languages, such as Ruby, IronPython, Magik and IronSmalltalk are all dynamically (or late) bound where the decision about where a method call ends up is taken at runtime.

Now if you declare an object as being dynamic the compiler will hold off, just as it would do naturally in a dynamic language. The method need not exist until runtime. The binding happens at runtime. SnagIt CaptureIf, like me, you rely heavily on intellisense to figure out if you are doing the right thing then you are going to have to get used to not having it. Since the call will be bound at runtime the compiler (and of course intellisense) won’t know whether a binding is valid or not. So, instead of regular intellisense you get a message simply saying “(dyanmic expression) This operation will be resolved at runtime.”

So, how do you get started with dynamic objects? I suppose the simplest example would be an object graph that is built at runtime that would normally have a fairly dynamic structure, say a nice XML file.

In this example, I’m going to take an XElement object (introduced in .NET 3.5) and wrap it in a new object type I’m creating called DynamicElement. This will inherit from DynamicObject (in the System.Dynamic namespace) which provides various bits of functionality that allows late binding.

using System.Dynamic;
using System.Linq;
using System.Xml.Linq;

namespace ColinAngusMackay.DynamicXml
{
    public class DynamicElement : DynamicObject
    {
        private XElement actualElement;

        public DynamicElement(XElement actualElement)
        {
            this.actualElement = actualElement;
        }

        public override bool TryGetMember(GetMemberBinder binder,
            out object result)
        {
            string name = binder.Name;

            var elements = actualElement.Elements(name);

            int numElements = elements.Count();
            if (numElements == 0)
                return base.TryGetMember(binder, out result);
            if (numElements == 1)
            {
                result = new DynamicElement(elements.First());
                return true;
            }

            result = from e in elements select new DynamicElement(e);
            return true;
        }

        public override string ToString()
        {
            return actualElement.Value;
        }
    }
}

The key method in this class is the override of the TryGetMember method. Everytime the runtime needs to resolve a method call it will call this method to work out what it needs to do.

In this example, all that happens is that if the name matches the name of a child element in the XML then that child element is returned. If there are multiple child elements with the same name then an enumerable collection of child elements is returned.

SnagIt CaptureIn the event that there is no match the method defers to the base class. If the binding fails then a RuntimeBinderException is thrown.

However, if the binding works you can make complex or ugly calls look much easier. For example. This program using the DynamicElement class to read the contents of an RSS feed:

using System;
using System.Xml.Linq;
using ColinAngusMackay.DynamicXml;

namespace ConsoleRunner
{
    class Program
    {
        static void Main(string[] args)
        {
            XElement xel = XElement.Parse(SampleXml.RssFeed);
            dynamic del = new DynamicElement(xel);

            Console.WriteLine(del.channel.title);
            Console.WriteLine(del.channel.description);

            foreach (dynamic item in del.channel.item)
                Console.WriteLine(item.title);

            Console.ReadLine();
        }
    }
}

The program starts off by reading in some XML into a regular XElement object. It it then wrapped up into the DynamicElement object, del.

The variable del is declared as a dynamic which lets compiler know that calls to its members will be resolved at runtime.

The program then uses the dynamic object to very easily navigate the XML. In this example, I’ve used the XML of the RSS feed for my blog.

The output of the program is:

SnagIt Capture

 

The barrier to entry for creating and using dynamic objects is quite low. It will be quite interesting to see how this new feature plays out.

Many people like the additional comfort that static binding at compile time provides as it means less things to go wrong at compile time. Advocates of dynamic binding often argue that if you are doing TDD then the tests will ensure that the application is running correctly.

Of course, dynamic binding, like any other language features, is open to abuse. I fully expect to see on forums examples of people who are using it quite wrongly and getting themselves into a terrible pickle as a result. This does not mean that dynamic objects are bad, it just means programmers need to learn how to use the tools they have correctly.

Caveat Programmator: This blog post is based on early preliminary information using Visual Studio 2010 / .NET Framework 4.0 Beta 1

Using a different map server with the Virtual Earth ASP.NET controls.

This uses the July 2008 CTP of the Windows Live tools. You can download the Windows Live Tools for Visual Studio.

One of the interesting features of Virtual Earth is that it doesn’t have to use the maps provided by Microsoft. You can set it up to point to another tile server so that you can use your own maps. This could be extremely useful for people who want to show static visualisations of data, or simply display something different to what Microsoft give you.

Setting up the tile server is likely the more difficult part as setting up the client to point at a new tile server is incredibly easy. I’m not going into setting up the tile server in this post.

First setting up the ASPX page to handle this:

<form id="form1" runat="server">
    <div>
       <asp:ScriptManager ID="ScriptManager1" runat="server"
         EnablePartialRendering="true" />
       <ve:Map ID="VEMap" runat="server" Height="600px" Width="600px"
         ZoomLevel="8" Center-Latitude="55.75" Center-Longitude="-3.5" />
    </div>
</form>

As you can see there isn’t anything unusual here. There are no additional options to set.

However, in the Page_Load event handler there are some things that need to be set up:

protected void Page_Load(object sender, EventArgs e)
{
    VEMap.DashboardSize = DashboardSize.Tiny;
    List<LatLongRectangle> bounds = CalculateBounds();
    TileSourceSpecification tileSpec = new TileSourceSpecification(
        "OSM", "", 1, bounds, 1, 18, "getTilePath", 1.0, 100, true);
    VEMap.AddTileLayer(tileSpec, true);
}
private static List<LatLongRectangle> CalculateBounds()
{
    List<LatLongRectangle> bounds = new List<LatLongRectangle>();
    LatLongRectangle box = new LatLongRectangle(
        new LatLong(90, -180), new LatLong(-90, 180));
    bounds.Add(box);
    return bounds;
}

First of all, we are reducing the dashboard side down to its minimum because the particular tile server does not support the other features provided in the dashboard such as switching between road and aerial photography.

We create the TileSourceSpecification that defines what the tile server can do and how to interact with it. The parameters are:

  • Id: An identifier for you to use to identify the tile server, if you are using more than one.
  • TileSource: You can set up a string format to define the URL of the tiles, but only if your tile server is using the same naming convention as Virtual Earth itself. It has the ability of switching between road, aerial and hybrid modes and load balancing. More info on the TileSource Property…
  • NumServers: If your tile server is load balanced then this specifies the number of servers.
  • Bounds: This is the bounding box of the tile layer. In our case above the tile server covers the entire world so our bounding box covers +90,-180 to -90,+180
  • MinZoomLevel / MaxZoomLevel: This pair of parameters specify the the minimum and maximum zoom levels. 1=the whole world, 18 = street level.
  • GetTilePath: This is the name of a javascript function that generates the path to the tile. I’ll go into more detail on that javascript function a little later on. However, if this property contains a value then the TileSource and NumServers properties are ignored.
  • Opacity: How opaque is this tile layer. By default the Virtual Earth tiles are drawn first, then your layer is drawn on top. 0 is completely transparent (and a bit pointless) while 1.0 is completely opaque and will hide the layer underneath. At present you cannot turn off the layer underneath so if you only want to see your layer set the opacity to 1.0. This is because Virtual Earth ASP.NET controls are based on Virtual Earth 6.1. 6.2 is now released which does have the ability to turn off the base layers.
  • ZIndex: Tile layers can be stacked on top of each other, this indicates the positioning of this layer in that stack.
  • Visible: Indicates whether the layer is visible or not.

In the example above the tile server does not support the virtual earth naming convention. In that case a javascript function to define the name of each tile is needed. In our example it looks like this:

function getTilePath(tileContext)
{
    return "http://tile.openstreetmap.org/" + tileContext.ZoomLevel +
         "/" + tileContext.XPos + "/" + tileContext.YPos + ".png";
}

The server for the tiles is http://tile.openstreetmap.org. If you are unfamiliar with it, Open Street Map is an open source map of the world.

The tile server refers to the individual tiles in the format “/{ZoomLevel}/{X}/{Y}.png”. These values can be obtained by the tileContext parameter (see right) passed into the javascript function.

The tile context also contains a map style property which can be “r” (road), “a” (aerial) or “h” (hybrid).

The final result looks like this:

For information about doing the same purely in javascript see this post by John O’Brien.

Follow

Get every new post delivered to your Inbox.