Using ASP.NET 5 Tag Helpers and the Bing Translator API

Update: In the latest version of ASP.NET 5, the GetChildContextAsync, that was previously available in the TagHelperContext class, is now in TagHelperOutput.

Introduction

If you’ve been following my posts you probably know that I have been a critic of MVC because of its poor support of reuse. Until now, the two main mechanisms for reuse – partial views and helper extensions – had some problems:

  • Partial views cannot be reused across projects/assemblies;
  • Helper methods cannot be easily extended.

Fortunately, ASP.NET 5 offers (good) solutions for these problems, in the form of Tag Helpers and View Components! This time, I’ll focus on tag helpers.

Tag Helpers

A tag helper behaves somewhat like a server-side control in ASP.NET Web Forms, without the event lifecycle. It sits on a view and can take parameters from it, resulting on the generation of HTML (of course, can have other side effects as well).

Tag helper can either be declared as new tags, ones that do not exist in HTML, such as <animation>, <drop-panel>, etc, or can intercept any tag, matching some conditions:

  • Having some pre-defined tag;
  • Being declared inside a specific tag;
  • Having some attributes defined;
  • Having a well-known structure, like, self-closing or without ending tag.

A number of these conditions can be specified, for example:

  • All IMG tags;
  • All A tags having an attribute of action-name;
  • All SPAN tags having both translate and from-language attributes;
  • All COMPONENT tags declared inside a COMPONENTS tag.

ASP.NET 5 includes a number of them:

  • AnchorTagHelper: generates links to action methods in controllers;
  • CacheTagHelper: caches its content for a number of seconds;
  • EnvironmentTagHelper: renders its content conditionally, depending on the current execution environment;
  • FormTagHelper: posts to an action method of a controller;
  • ImageTagHelper: adds a suffix to an image URL, to control caching of the file;
  • InputTagHelper
  • LabelTagHelper
  • LinkTagHelper
  • OptionTagHelper
  • ScriptTagHelper
  • SelectTagHelper
  • TextAreaTagHelper
  • ValidationMessageTagHelper: outputs model validation messages;
  • ValidationSummaryTagHelper: outputs a validation summary.

In order to use tag helpers, we need to add a reference to the Microsoft.AspNet.Mvc.TagHelpers Nuget package in Project.json (at the time this post was written, the last version was 6.0.0-beta8):

"dependencies": {

    ...

    "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-beta8"

}

Enough talk, let’s see an example of the TagHelper class with some HtmlTargetElement attributes (no API documentation available yet):

[HtmlTargetElement("p", Attributes = "translate, to-language")]

[HtmlTargetElement("span", Attributes = "translate, to-language")]

public sealed class TranslateTagHelper : TagHelper

{

}

This tag helper will intercept the following tag declarations, inside a view:

<p translate="true" to-language="pt">This is some text meant for translation</p>

<span translate="true" to-language="pt">Same here</span>

Tag helpers need to be declared in a view before they can be used. They can come from any assembly:

@addTagHelper "*, MyNamespace"

Properties declared on the markup will be automatically mapped to properties on the TagHelper class. Special names, such as those having , will require an HtmlAttributeName attribute:

[HtmlAttributeName("to-language")]

public string ToLanguage { get; set; }

If, on the other hand, we do not want such a mapping, all we have to do is apply an HtmlAttributeNotBound attribute:

[HtmlAttributeNotBound]

public string SomeParameter { get; set; }

The TagHelper class defines two overridable methods:

  • Process: where the logic is declared, executes synchronously;
  • ProcessAsync: same as above, but executes asynchronously.

We only need to override one. In it, we have access to the passed attributes, the content declared inside the tag and its execution context:

public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)

{

    var content = await context.GetChildContentAsync();

    var text = content.GetContent();


    //do something with content


    content.TagName = "DIV";

    content = output.Content.Clear();

    content = output.Content.Append("HTML content");

}

You can see that I am redefining the output tag, in this case, to DIV, and, also, I am clearing all content and replacing it with my own.

Now, let’s see a full example!

Content Translation

Microsoft makes available for developers the Bing Translator API. It allows, at no cost (for a reasonable number of requests) to perform translations of text through a REST interface (several API bindings exist that encapsulate it). Let’s implement a tag helper that will automatically translate any text contained inside of it.

In order to use this API, you first need to register at the Microsoft Azure Marketplace. Then, we need to create a Marketplace application. After we do that, we need to generate an authorization key. There are several tools that can do this, in my case, I use Postmap, a Google Chrome extension that allows the crafting and execution of REST requests.

The request for generating an authorization key goes like this:

POST https://datamarket.accesscontrol.windows.net/v2/OAuth2-13

grant_type: client_credentials

client_id: <client id>

client_secret: <client secret>

scope: http://api.microsofttranslator.com

The parameters <client id> and <client secret> are obtained from our registered applications’ page and grant_type, client_id, client_secret and scope are request headers. The response should look like this:

{
“token_type”: “
http://schemas.xmlsoap.org/ws/2009/11/swt-token-profile-1.0″,
“access_token”: “<access token>“,
“expires_in”: “600”,
“scope”: “
http://api.microsofttranslator.com”

}

Here, what interests us is the <access token> value. This is what we’ll use to authorize a translation request. The value for expires_in is also important, because it contains the amount of time the access token is valid.

A translation request should look like this:

GET http://api.microsofttranslator.com/V2/Ajax.svc/Translate?to=<target language>&text=<text to translate>&from=<source language>

Authorization: Bearer <access token>

The <target language> and <text> parameters are mandatory, but the <source language> one isn’t; if it isn’t supplied, Bing Translator will do its best to infer the language of the <text>. Authorization should be sent as a request header.

Let’s define an interface for representing translation services:

public interface ITranslationService

{

    Task<string> TranslateAsync(string text, string to, string @from = null);

}

Based on what I said, a Bing Translator implementation could look like this:

public sealed class BingTranslationService : ITranslationService

{

    public const string Url = "http://api.microsofttranslator.com/V2/Ajax.svc/Translate?text={0}&to={1}&from={2}";


    public string AuthKey { get; set; }


    public async Task<string> TranslateAsync(string text, string to, string @from = null)

    {

        using (var client = new HttpClient())

        {

            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", this.AuthKey);


            var result = await client.GetStringAsync(new Uri(string.Format(Url, WebUtility.UrlEncode(text), to, from)));


            return result;

        }

    }

}

Let’s register this service in ConfigureServices:

services.AddSingleton<ITranslationService>((sp) => new BingTranslationService { AuthKey = "<access token>" });

Of course, do replace <access token> by a proper one, otherwise your calls will always fail.

Caching

In order to make our solution more scalable, we will cache the translated results, this way, we avoid unnecessary – and costly – network calls. ASP.NET 5 offers two caching contracts, IMemoryCache and IDistributedCache. For the sake of simplicity, let’s focus on IMemoryCache, On the ConfigureServices method of the Startup class let’s add the caching services:

services.AddCaching();

And now let’s see it all together.

Putting it All Together

The final tag helper looks like this:

[HtmlTargetElement("p", Attributes = "translate, to-language")]

[HtmlTargetElement("span", Attributes = "translate, to-language")]

public sealed class TranslateTagHelper : TagHelper

{

    private readonly ITranslationService svc;

    private readonly IMemoryCache cache;


    public TranslateTagHelper(ITranslationService svc, IMemoryCache cache)

    {

        if (svc == null)

        {

            throw new ArgumentNullException(nameof(svc));

        }


        this.svc = svc;

        this.cache = cache;

    }


    [HtmlAttributeName("from-language")]

    public string FromLanguage { get; set; }


    [HtmlAttributeName("to-language")]

    public string ToLanguage { get; set; }


    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)

    {

        if (string.IsNullOrWhiteSpace(this.ToLanguage) == true)

        {

            throw new InvalidOperationException("Missing target language.");

        }


        var content = await context.GetChildContentAsync();

        var text = content.GetContent();


        if (string.IsNullOrWhiteSpace(text) == true)

        {

            return;

        }


        var cacheKey = $"{this.FromLanguage}:{text.ToLowerInvariant().Trim()}:{this.ToLanguage}";

        var response = string.Empty;


        this.cache?.TryGetValue(cacheKey, out response);


        if (string.IsNullOrWhiteSpace(response) == true)

        {

            response = await svc.TranslateAsync(text, this.ToLanguage, this.FromLanguage);

            response = response.Trim('"');


            cache?.Set(cacheKey, response);

        }


        content = output.Content.Clear();

        content = output.Content.Append(response);

    }

}

It tries to obtain the translated context from the cache – if it is registered – otherwise, it will issue a translation request. If it succeeds, it stores the translation in the cache. The cache key is a combination of the text (in lowercase), the source and destination languages. The only strictly required service is an implementation of our ITranslationService, the cache is optional. In order use the tag in a view, all we need is:

@addTagHelper "*, MyNamespace"


<p translate="yes" to-language="pt">This is some translatable content</p>

Conclusion

I hope I managed to convince you of the power of tag helpers. They are a powerful mechanism and a welcome addition to ASP.NET MVC. Looking forward to hearing what you can do with them!

The Evolution of .NET Dependency Resolution

Introduction

Dependency Resolution (RS), Dependency Injection (DI) and Inversion of Control (IoC) are hot topics nowadays. Basically all frameworks are aware of it, or offer some mechanisms to help implement it. It all started a long time ago, however, and things are slightly confusing at the moment – but will get better!

In this post, I won’t go through all of the details of all dependency resolution libraries in existence, instead I will only focus on Microsoft libraries. Also, I will only talk about generic dependency resolution, leaving out more specialized usages, such as WCF, WF and SharePoint, which also use similar concepts.

Origins

It all started with the venerable IServiceProvider interface. It basically provided a single method, GetService, that gave answer to “get me an implementation for this type”. That was it, the single parameter was a Type, and the response, a single object. There were no public implementations of it, but Windows Forms designers – auto generated code – used it a lot to request services from the design surfaces (aka, Visual Studio designer). You were free to implement it in any way, the only recommendation was to return null in case no service could be found, instead of throwing an exception.

ASP.NET MVC

ASP.NET MVC started as a built-in template option in Visual Studio but then migrated to NuGet deployment, which is how Microsoft now delivers its fast-moving libraries. MVC 4 introduced its own dependency injection container and API. It was built around IDependencyResolver interface, which did not implement IServiceProvider. although it offered a GetService method that had exactly the same signature – and requirements – as IServiceProvider’s. It also added another method, GetServices, for retrieving all implementations of a given service, again identified by its Type.

This time we had a registration point, which was DependencyResolver.Current. You could set it to your custom implementation, or use the default, which didn’t really return anything.

ASP.NET Web API

Web API came out a bit later than MVC, and, while sharing its philosophy, and also being delivered through NuGet, offered its own APIs, namely, for dependency injection. There was also a IDependencyResolver interface, again, not inheriting from IServiceProvider, but with a slightly more complex inheritance: now we had also IDependencyScope, which was where the GetService and GetServices methods were declared, as well as IDisposable, supposedly so that we could have dependency resolution scopes. The well-known registration point was GlobalConfiguration.Configuration.DependencyResolver.

ASP.NET SignalR

SignalR was something of an outsider in the ASP.NET stack. Like MVC and Web API, it was offered (and still is, for that matter) as a separate NuGet package. No wonder that it also offered its own dependency resolution API, in the form of IDependencyResolver. Again, not related to IServiceProvider, and as such offered a couple of other methods: besides the classic GetService (same signature and contract), we also had GetServices, and even a registration method (RegisterType with a couple of overloads). It was also IDisposable, perhaps to control registration scopes. The registration point was available as GlobalHost.DependencyResolver and there was a default implementation, appropriately named DefaultDependencyResolver.

Entity Framework 6

Leaving ASP.NET land for a moment, Entity Framework 6 also introduced its own (of course…) API for dependency resolution. The IDbDependencyResolver also offered the now classic GetService and GetServices methods, but this time, these also took an optional key parameter. GetService should not throw if a matching service was not found, and GetServices should return an empty enumeration likewise. The registration was done through DbConfiguration.DependencyResolver, no public default implementation. EF 6 expected a number of services to be supplied through dependency resolution, otherwise, it would use its own built-in defaults.

Entity Framework 7

Although still in pre-release, EF 7 shuffles things a bit. For once, the DbContext constructor can now take an instance of IServiceProvider. More details coming soon, I guess, but apparently it seems to be going back to the roots.

Unity

Unity is part of Microsoft’s Enterprise Library and long time readers of my blog should know that it’s what I normally use for inversion of control (IoC), dependency injection (DI) and aspect-oriented programming (AOP). Being an IoC container, it includes its own API, IUnityContainer, which also offered service resolution methods, besides lots of other stuff; this time, the names are Resolve and ResolveAll, with several overloads and generic as well as non-generic versions. Resolve can take an optional key, but a major difference is that the default implementation (UnityContainer) will throw an exception if a service is not found.

Common Service Locator

Because there are lots of dependency resolution libraries out there, offering conceptually similar services but with different APIs, Microsoft sponsored an open-source library for defining a common interface for dependency resolution to which interested parties could comply, or, better, write an adapter for. The code is available in Codeplex and NuGet and several library authors provided adapters for the Common Service Locator, such as Unity, Castle Windsor, Spring.NET, StructureMap, Autofac, MEF, LinFu, Ninject, etc. See a list of NuGet packages matching Common Service Locator here. The Common Service Locator API only prescribes two families of methods in its IServiceLocator API: GetInstance and GetAllInstances. Interestingly, IServiceLocator inherits from IServiceProvider, and it also features an optional key for GetInstance, like EF6 and Unity, as this is the more general case – multiple registrations for the same type under different keys, the default key is null.

ASP.NET 5

ASP.NET 5 is just around the corner, and Microsoft seems to me to be moving in the right direction. MVC, Web API and SignalR are merged together, so the dependency resolution mechanisms should be the same. The IServicesCollection (sorry, no public API documentation) interface allows for the registration and the resolution of services through the conventional Startup.ConfigureServices method and is made available in the HttpContext and IApplicationBuilder implementations as the ApplicationServices and RequestServices properties, of type IServiceProvider. Not that you typically need it, but the default implementation of IServicesCollection is ServicesCollection, and one key difference is that you do not have a global entrypoint to it, you can only access it through the current HttpContext reference, in most cases.

Conclusion

That’s it. Looking forward for your feedback on this.

Persisting SignalR Connections Across Page Reloads

I recently had the need to keep a SignalR connection even if the page would reload. As far as I know, this cannot be done out of the box, either with hubs or persistent connections. I looked it up, but could find no solid solution, so here is my solution!

First, we need to create a “session id” that is to be stored at the browser side. Mind you, this is not an ASP.NET session, nor a SignalR connection id, it’s something that uniquely identifies a session. To maintain sessions we normally use cookies, but my solution uses instead HTML5 session storage. I had to generate a session id, and there were several solutions available, from pseudo-GUIDs, to the SignalR connection id, but I ultimately decided to use the timestamp; here is it:

function getSessionId()

{

    var sessionId = window.sessionStorage.sessionId;

    

    if (!sessionId)

    {

        sessionId = window.sessionStorage.sessionId = Date.now();

    }

    

    return sessionId;

}

As you can see, this function first checks to see if the session id was created, by inspecting the sessionStorage object, and, if not, sets it.

Next, we need to have SignalR pass this session id on every request to the server. For that, I used $.connection.hub.qs, the query string parameters object:

$.connection.hub.qs = { SessionId: getSessionId() };

$.connection.hub.start().done(function ()

{

    //connection started

});

Moving on to the server-side, I used a static collection to store, for each session id, each SignalR connection id associated with it – one for each page request. The reasoning is, each page reload generates a new SignalR connection id, but the session id is always kept:

public sealed class NotificationHub : Hub

{

    internal const string SessionId = "SessionId";

 

    public static readonly ConcurrentDictionary<string, HashSet<string>> sessions = new ConcurrentDictionary<string, HashSet<string>>();

 

    public static IEnumerable<string> GetAllConnectionIds(string connectionId)

    {

        foreach (var session in sessions)

        {

            if (session.Value.Contains(connectionId) == true)

            {

                return session.Value;

            }

        }

 

        return Enumerable.Empty<string>();

    }

 

    public override Task OnReconnected()

    {

        this.EnsureGroups();

 

        return base.OnReconnected();

    }

 

    public override Task OnConnected()

    {

        this.EnsureGroups();

 

        return base.OnConnected();

    }

 

    private void EnsureGroups()

    {

        var connectionIds = null as HashSet<string>;

        var sessionId = this.Context.QueryString[SessionId];

        var connectionId = this.Context.ConnectionId;

 

        if (sessions.TryGetValue(sessionId, out connectionIds) == false)

        {

            connectionIds = sessions[sessionId] = new HashSet<string>();

        }

 

        connectionIds.Add(connectionId);

    }

}

As you can see, both on OnConnected as in OnReconnected, I add the current connection id to the collection (ConcurrentDictionary<TKey, TValue> to allow multiple concurrent accesses) indexed by the session id that I sent in the SignalR query string. Then, I have a method that looks in the collection for all connection id entries that are siblings of a given connection id. If more than one exists, it means that the page has reloaded, otherwise, there will be a one-to-one match between connection ids and session ids.

The final step is to broadcast a message to all the sibling connection ids – a waste of time because only one is still possibly active, but since we have no way of knowing, it has to be this way:

[HttpGet]

[Route("notify/{connectionId}/{message}")]

public IHttpActionResult Notify(string connectionId, string message)

{

    var context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();

    var connectionIds = NotificationHub.GetAllConnectionIds(connectionId).ToList();

 

    context.Clients.Clients(connectionIds).MessageReceived(message);

 

    return this.Ok();

}

This Web API action method will get the context for our hub (NotificationHub), look up all of the sibling connection ids for the passed one, and then broadcast a message to all clients identified by these connection ids. It’s a way to send messages from outside of a page into a hub’s clients

Problems with this approach:

  • All tabs will get the same session id, but that also happens with cookies;
  • Although unlikely, it may be possible for two clients to get the same session id, which I implemented as the current timestamp; an easy fix would be, for example, to use a pseudo-GUID, the server-side session id, or even the SignalR connection id;
  • If the page reloads several times, there will be several connection id entries for the same session id – which will be kept throughout all reloads; no easy way to get around this, except possibly using some cache with expiration mechanism.

And that’s it. Enjoy!

SharePoint Pitfalls: Master Pages in Page Layouts

When you deploy a page layout, you may want to add your own master page as well. I find it useful to add my own custom master pages and reference them directly, in the same or a dependent feature. You might be surprised, however, that it doesn’t work exactly how you’d expect!

The issue is, page layouts will ignore silently anything in the MasterPageFile attribute if it isn’t one of the standard tokens for the system or custom master pages. ~masterurl/default.master and ~masterurl/custom.master. The solution is to have a code behind class and specify the master page in the OnPreInit method (anywhere else won’t work):

protected override void OnPreInit(EventArgs e)

{

    base.OnPreInit(e);

 

    this.MasterPageFile = "~site/_catalogs/masterpage/CustomMasterPage.master":

}

SharePoint Pitfalls Index

This page will list all of my posts dedicated to SharePoint pitfalls. It will be updated regularly.

  1. Creating a Visual Studio Project Without SharePoint Locally Installed
  2. Save Publishing Site as Template Option Missing
  3. Publishing Pages in Document Libraries Other Than Pages

SharePoint Pitfalls: Publishing Pages in Document Libraries Other Than Pages

This one is a classic: the SharePoint Publishing feature in a Publishing Site creates a document library by the name of Pages; this is where you can store your publishing pages.

A common request is to have more of these document libraries, that is because we cannot create publishing pages anywhere else. The problem is, it is unsupported, God knows why!

What you can do is rename the document library to something else. SharePoint will look for the library id in the site’s property bag, under __PagesListId, so only need to update this value accordingly:

web.AllProperties["__PagesListId"] = newDocLibId.ToString();

web.Update();

Now, there are some solutions over the Internet that claim to go around this limitation, but none of them is supported, so proceed with care!

Case Study: Comparing ASP.NET Web Forms and MVC Implementations

Introduction

Apparently, I am the last ASP.NET Web Forms developer in the whole World, which makes me kind of sad… anyway, after much crying, I decided to try out something: a comparison of Web Forms and MVC to solve a real life problem! Now, I only needed a problem to solve… Then, a colleague of mine came questioning me about captchas, so I thought, why not use it as my example? And here we are!

Everyone is familiar with captchas. They are a way to prevent the automated use of web forms, so as to make sure that it is indeed an human that is providing the information. There are lots of implementations out there, and I don’t claim that mine is better or worse, I just implemented it in a couple of hours as an exercise.

Core Library

I designed a couple of classes, framework-agnostic, to hold my abstractions and sample implementations. These are:

Common

A succinct description is in order.

CaptchaSecretPersister

The contract for storing a secret key. Defines two methods, Store and Retrieve.

SessionCaptchaSecretPersister

An implementation of CaptchaSecretPersister that stores the secret key in the ASP.NET session.

CaptchaImageTransformer

The contract for transforming an image. Only has a single method, Transform.

NullCaptchaImageTransformer

Inherits from CaptchaImageTransformer, but doesn’t do anything.

CaptchaSecretGenerator

The contract for generating a new secret key (GetSecret).

RandomCaptchaSecretGenerator

An implementation of CaptchaSecretGenerator that generates a series of random letters.

CaptchaImageProducer

Base class for producing an image with a given secret key, dimensions, colors and an optional image transformer. Only has a single method, GetImage.

GdiCaptchaImageProducer

An implementation of CaptchaImageProducer that uses GDI+.

CaptchaSecretValidator

Base contract for secret key validation. Only defines a method, Validate.

CaseInsensitiveCaptchaSecretValidator

A case-insensitive string comparison implementation of CaptchaSecretValidator.

And here is their code:

public abstract class CaptchaSecretPersister

{

    public abstract void Store(String secret);

 

    public abstract String Retrieve();

}

 

public sealed class SessionCaptchaSecretPersister : CaptchaSecretPersister

{

    public static readonly CaptchaSecretPersister Instance = new SessionCaptchaSecretPersister();

 

    internal const String Key = "Captcha";

 

    public override void Store(String secret)

    {

        HttpContext.Current.Session[Key] = secret;

    }

 

    public override String Retrieve()

    {

        return HttpContext.Current.Session[Key] as String;

    }

}

 

public abstract class CaptchaImageTransformer

{

    public abstract void Transform(Graphics g);

}

 

public sealed class NullCaptchaImageTransformer : CaptchaImageTransformer

{

    public static readonly CaptchaImageTransformer Instance = new NullCaptchaImageTransformer();

 

    public override void Transform(Graphics g)

    {

        //do nothing

    }

}

 

public abstract class CaptchaSecretGenerator

{

    public abstract String GetSecret(UInt32 length);

}

 

public sealed class RandomCaptchaSecretGenerator : CaptchaSecretGenerator

{

    public static readonly CaptchaSecretGenerator Instance = new RandomCaptchaSecretGenerator();

 

    public override String GetSecret(UInt32 length)

    {

        var builder = new StringBuilder();

        var rand = new Random();

 

        for (var i = 0; i < length; i++)

        {

            var ch = (Char)('A' + rand.Next(26));

            builder.Append(ch);

        }

 

        return builder.ToString();

    }

}

 

public abstract class CaptchaImageProducer

{

    public abstract Image GetImage(Int32 width, Int32 height, String secret, Color foreColor, Color backColor, CaptchaImageTransformer transformer);

}

 

public sealed class GdiCaptchaImageProducer : CaptchaImageProducer

{

    public static readonly CaptchaImageProducer Instance = new GdiCaptchaImageProducer();

 

    public override Image GetImage(Int32 width, Int32 height, String secret, Color foreColor, Color backColor, CaptchaImageTransformer transformer)

    {

        var img = new Bitmap(width, height, PixelFormat.Format32bppArgb);

 

        using (var graphics = Graphics.FromImage(img))

        using (var font = new Font(FontFamily.GenericSansSerif, 10F))

        using (var color = new SolidBrush(foreColor))

        {

            graphics.TextRenderingHint = TextRenderingHint.AntiAlias;

            graphics.Clear(backColor);

            graphics.DrawString(secret, font, color, 0F, 0F);

 

            if (transformer != null)

            {

                transformer.Transform(graphics);

            }

 

            return img;

        }

    }

}

 

public abstract class CaptchaSecretValidator

{

    public abstract Boolean Validate(String storedSecret, String secret);

}

 

public sealed class CaseInsensitiveCaptchaSecretValidator : CaptchaSecretValidator

{

    public static readonly CaptchaSecretValidator Instance = new CaseInsensitiveCaptchaSecretValidator();

 

    public override Boolean Validate(String storedSecret, String secret)

    {

        return String.Equals(storedSecret, secret, StringComparison.OrdinalIgnoreCase);

    }

}

Noteworthy:

  • Base classes are always abstract;
  • Actual implementations are sealed, stateless, and therefore define a static read only field, to avoid multiple instantiations.

Both implementations, Web Forms and MVC, will use these classes.

Web Forms

So let’s start playing. Web Forms has the concept of validators. A validator must implement interface IValidator, and a BaseValidator class exists to make the task easier. When a form is submitted by a control that triggers validation, such as Button, all registered validators (Page.Validators) of the same validation group (ValidationGroup) as the trigger control are fired (Validate is called). The page will be considered valid if all validators have their IsValid property set to true. Knowing this, I created a custom control to display the captcha image and perform its validation:

public sealed class CaptchaImage : WebControl, IValidator

{

    public CaptchaImage() : base(HtmlTextWriterTag.Img)

    {

        this.CaptchaSecretGenerator = RandomCaptchaSecretGenerator.Instance;

        this.CaptchaImageTransformer = NullCaptchaImageTransformer.Instance;

        this.CaptchaImageProducer = GdiCaptchaImageProducer.Instance;

        this.CaptchaSecretPersister = SessionCaptchaSecretPersister.Instance;

        this.CaptchaSecretValidator = CaseInsensitiveCaptchaSecretValidator.Instance;

 

        this.CaptchaLength = 4;

        this.CaptchaFormat = ImageFormat.Png;

 

        this.ForeColor = Color.Black;

        this.BackColor = Color.Transparent;

        this.AlternateText = String.Empty;

        this.ControlToSetError = String.Empty;

        this.ControlToValidate = String.Empty;

 

        (this as IValidator).IsValid = true;

    }

 

    public CaptchaSecretPersister CaptchaSecretPersister { get; set; }

 

    public CaptchaSecretGenerator CaptchaSecretGenerator { get; set; }

 

    public CaptchaImageTransformer CaptchaImageTransformer { get; set; }

 

    public CaptchaImageProducer CaptchaImageProducer { get; set; }

 

    public CaptchaSecretValidator CaptchaSecretValidator { get; set; }

 

    [DefaultValue("")]

    public String AlternateText { get; set; }

 

    [DefaultValue(4)]

    public UInt32 CaptchaLength { get; set; }

 

    [DefaultValue(typeof(ImageFormat), "Png")]

    public ImageFormat CaptchaFormat { get; set; }

 

    [DefaultValue("")]

    [IDReferenceProperty]

    [TypeConverter(typeof(ControlIDConverter))]

    public String ControlToValidate { get; set; }

 

    [DefaultValue("")]

    [IDReferenceProperty]

    [TypeConverter(typeof(ControlIDConverter))]

    public String ControlToSetError { get; set; }

 

    [DefaultValue("")]

    public String ErrorMessage { get; set; }

 

 

    public event EventHandler ValidationSuccess;

    public event EventHandler ValidationFailure;

    public event EventHandler ValidationComplete;

 

    private void OnValidationSuccess()

    {

        var handler = this.ValidationSuccess;

 

        if (handler != null)

        {

            handler(this, EventArgs.Empty);

        }

    }

 

    private void OnValidationComplete()

    {

        var handler = this.ValidationComplete;

 

        if (handler != null)

        {

            handler(this, EventArgs.Empty);

        }

    }

 

    private void OnValidationFailure()

    {

        var handler = this.ValidationFailure;

 

        if (handler != null)

        {

            handler(this, EventArgs.Empty);

        }

    }

    

    private ITextControl FindTextControl(String id)

    {

        return this.NamingContainer.FindControl(id) as ITextControl;

    }

 

    protected override void OnInit(EventArgs e)

    {

        if (this.Enabled == true)

        {

            this.Page.Validators.Add(this);

        }

 

        base.OnInit(e);

    }

 

    protected override void Render(HtmlTextWriter writer)

    {

        var secret = this.CaptchaSecretGenerator.GetSecret(this.CaptchaLength);

 

        this.CaptchaPersister.Store(secret);

 

        using (var img = this.CaptchaImageProducer.GetImage((Int32)this.Width.Value, (Int32)this.Height.Value, secret, this.ForeColor, this.BackColor, this.CaptchaImageTransformer))

        using (var stream = new MemoryStream())

        {

            img.Save(stream, this.CaptchaFormat);

 

            this.Attributes[HtmlTextWriterAttribute.Src.ToString().ToLower()] = String.Format("data:image/{0};base64,{1}", this.CaptchaFormat.ToString().ToLower(), Convert.ToBase64String(stream.ToArray()));

            this.Attributes[HtmlTextWriterAttribute.Alt.ToString().ToLower()] = this.AlternateText;

        }

 

        base.Render(writer);

 

        var val = this as IValidator;

 

        if (val.IsValid == false)

        {

            var errorControl = this.FindTextControl(this.ControlToSetError);

 

            if (errorControl != null)

            {

                errorControl.Text = this.ErrorMessage;

            }

            else

            {

                writer.Write(this.ErrorMessage);

            }

        }

    }

 

    Boolean IValidator.IsValid { get; set; }

 

    void IValidator.Validate()

    {

        var val = this as IValidator;

        val.IsValid = true;

 

        var secretControl = this.FindTextControl(this.ControlToValidate);

        

        if (secretControl != null)

        {

            var storedSecret = this.CaptchaSecretPersister.Retrieve();

 

            val.IsValid = this.CaptchaSecretValidator.Validate(storedSecret, secretControl.Text);

 

            if (val.IsValid == true)

            {

                this.OnValidationSuccess();

            }

            else

            {

                this.OnValidationFailure();

            }

 

            this.OnValidationComplete();

        }

    }

}

The CaptchaImage class inherits from WebControl, so that we can leverage some of its properties (ForeColor, BackColor), and defines a containing tag of IMG.

In its constructor, all relevant properties are instantiated to sensible defaults, these include a number of properties for the core library classes (CaptchaSecretPersister, CaptchaSecretGenerator, CaptchaImageProducer, CaptchaImageTransformer and CaptchaSecretValidator). Other important properties are:

  • ErrorMessage: the message to display in case of a validation error;
  • AlternateText: the image’s ALT text;
  • CaptchaLength: the desired length of the secret key; the default is 4;
  • CaptchaFormat: the image format of choice, where the default is ImageFormat.Png;
  • ControlToValidate: the required ID of a server-side control containing text (must implement ITextControl);
  • ControlToSetError: an optional ID for a control that can take text (must implement ITextControl too), which will be used to set the ErrorMessage value.

The IsValid property, from IValidator, is implemented privately because most of the time we do not want to mess with it. Another inherited property, Enabled, can be used to turn off validation.

Then we have three events:

  • ValidationSuccess: raised when the validation occurs and is successful;
  • ValidationFailure: raised when a failed validation occurs;
  • ValidationComplete: always raised when a validation is performed, regardless of its outcome.

When the control loads, OnInit is called, and it registers itself with the Validators collection, this is a required step. In Render, it generates a secret key, stores it, produces an image from it and renders it as an inline image using the Data URI format. It is the same approach that I talked about a number of times before. When the control receives a validation request, the Validate method is called, and the provided key is validated against the stored one.

A typical usage would be like this:

<web:CaptchaImage runat="server" ID="captcha" Width="50px" Height="25px" BackColor="Blue" AlternateText="Captcha riddle" ControlToValidate="text" ErrorMessage="Invalid captcha" OnValidationSuccess="OnSuccess" OnValidationFailure="OnFailure" OnValidationComplete="OnComplete" />

Whereas the registered event handlers might be:

protected void OnSuccess(Object sender, EventArgs e)

{

    this.captcha.Visible = false;

}

 

protected void OnFailure(Object sender, EventArgs e)

{

}

 

protected void OnComplete(Object sender, EventArgs e)

{

}

Easy, don’t you think? Now, let’s move on to MVC!

MVC

In MVC we don’t really have controls, because of the separation of concerns and all that. The closest we have at the moment are extension methods, let’s have a look at the Captcha method:

public static IHtmlString Captcha(this HtmlHelper html, Int32 width, Int32 height, UInt32 length = 4, String alternateText = "", ImageFormat captchaFormat = null, Color? foreColor = null, Color? backColor = null)

{

    var captchaSecretGenerator = DependencyResolver.Current.GetService<CaptchaSecretGenerator>();

    var captchaSecretPersister = DependencyResolver.Current.GetService<CaptchaSecretPersister>();

    var captchaImageProducer = DependencyResolver.Current.GetService<CaptchaImageProducer>();

    var captchaImageTransformer = DependencyResolver.Current.GetService<CaptchaImageTransformer>();

 

    var secret = captchaSecretGenerator.GetSecret(length);

 

    captchaSecretPersister.Store(secret);

 

    using (var img = captchaImageProducer.GetImage(width, height, secret, foreColor ?? Color.Black, backColor ?? Color.Transparent, captchaImageTransformer))

    using (var stream = new MemoryStream())

    {

        img.Save(stream, captchaFormat ?? ImageFormat.Png);

 

        var tag = String.Format("<img src=\"data:image/{0};base64,{1}\" width=\"{1}\" height=\"{2}\" alt=\"{3}\"/>", (captchaFormat ?? ImageFormat.Png).ToString().ToLower(), Convert.ToBase64String(stream.ToArray()), width, height, alternateText);

 

        return new HtmlString(tag);

    }

}

It is unpractical to pass all components, so we are relying on MVC’s built-in dependency injection framework. I used Microsoft Unity as my Inversion of Control (IoC) container, and to make it integrate with MVC, I installed the Unity.Mvc NuGet package:

image

Then I had to register the actual implementations for my services, this is usually done in the App_Start\UnityConfig.cs file’s RegisterTypes method:

container.RegisterInstance<CaptchaSecretGenerator>(RandomCaptchaSecretGenerator.Instance);

container.RegisterInstance<CaptchaImageProducer>(GdiCaptchaImageProducer.Instance);

container.RegisterInstance<CaptchaSecretPersister>(SessionCaptchaSecretPersister.Instance);

container.RegisterInstance<CaptchaImageTransformer>(NullCaptchaImageTransformer.Instance);

container.RegisterInstance<CaptchaSecretValidator>(CaseInsensitiveCaptchaSecretValidator.Instance);

The code from Unity.Mvc automatically hooks Unity with the DependencyResolver class, so we don’t have to do it ourselves. For an example implementation, I once wrote a post on it that you can check out, if you are curious.

Now, we need two things: a view and a controller. Let’s look at the view first (simplified):

@Html.Captcha(50, 25)

@using (Html.BeginForm("Validate", "Home"))

{

    @Html.TextBox("secret")

    <button>Validate</button>

}

As you can see, the form will post to the Validate method of an HomeController. The output of the Captcha method doesn’t have to be inside the form, because it merely renders an IMG tag.

As for the controller, the Validate method is pretty straightforward:

public ActionResult Validate(String secret)

{

    var captchaPersister = DependencyResolver.Current.GetService<CaptchaSecretPersister>();

    var captchaSecretValidator = DependencyResolver.Current.GetService<CaptchaSecretValidator>();

 

    var storedSecret = captchaPersister.Retrieve();

    var isValid = captchaSecretValidator.Validate(storedSecret, secret);

 

    if (isValid == true)

    {

        return this.View("Success");

    }

    else

    {

        return this.View("Failure");

    }

}

It tries to obtain the services from the DependencyResolver, validates the supplied secret key and then returns the proper view, accordingly.

Conclusion

So, which implementation do you prefer? The Web Forms one, unsurprisingly, only needs a single class, CaptchaImage, and, of course, a host page; the assembly containing it can be referenced by other projects and used very easily. As for the MVC version, we need to have the Captcha extension method, the IoC bootstrapping/registration code, a view and a controller with a Validate method similar to the one presented. The extension method and the controller may come from another referenced assembly, it needs some work, but can definitely be done.

Of course, this is a sample implementation, things can be done in a myriad of alternative ways. I’d like to hear from you about the problems with this particular implementation, and alternative ways to do it. By the way, feel free to use and modify the code anyway you want to, I will soon make it available in my GitHub account.

Generating GDI+ Images for ASP.NET MVC Views

This post is about applying the same technique I presented for ASP.NET Web Forms, but this time for MVC.

We need to have an ActionResult that does the actual work of converting whatever we draw in the Graphics context into an image with an inline Data URI. Here’s a possible solution, where you only specify the dimensions of the image to be generated:

public sealed class InlineImageResult : ActionResult

{

    private readonly Image bmp;

 

    public InlineImageResult(Int32 width, Int32 height)

    {

        //the PixelFormat argument is required if we want to have transparency

        this.bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);

 

        this.Graphics = Graphics.FromImage(this.bmp);

        //for higher quality

        this.Graphics.CompositingQuality = CompositingQuality.HighQuality;

        this.Graphics.SmoothingMode = SmoothingMode.HighQuality;

        this.Graphics.InterpolationMode = InterpolationMode.High;

        //make the background transparent

        this.Graphics.Clear(Color.Transparent);

    }

 

    public Graphics Graphics { get; private set; }

 

    public override void ExecuteResult(ControllerContext context)

    {

        using (this.bmp)

        using (this.Graphics)

        using (var stream = new MemoryStream())

        {

            //PNG because of transparency

            var format = ImageFormat.Png;

 

            this.bmp.Save(stream, format);

 

            var img = String.Format("<img src=\"data:image/{0};base64,{1}\"/>", format.ToString().ToLower(), Convert.ToBase64String(stream.ToArray()));

 

            context.HttpContext.Response.Write(img);

        }

    }

}

Now, we need to create an instance of this result and draw in it, in a controller’s action method:

[ChildActionOnly]

public ActionResult Image()

{

    var result = new InlineImageResult(200, 50);

    result.Graphics.DrawString("Hello, World!", new Font("Verdana", 20, FontStyle.Regular, GraphicsUnit.Pixel), new SolidBrush(Color.Blue), 0, 0);

 

    return result;

}

Notice the ChildActionOnly attribute: it tells MVC that this action method is only meant to be used in child action (RenderAction) call, not as a stand-alone action, like this:

<p>

    @{ Html.RenderAction("Image"); }

</p>

As you can see, this provides a very convenient way to generate images on the fly. You just need to learn about the drawing methods in GDI+.

SharePoint Pitfalls: Save Publishing Site as Template Option Missing

If you want to save a publishing site as a template, so that it can be used to create other sites, you may find it surprising that the option is missing from the site settings page:

image

I don’t know exactly why, but publishing sites hide this option, however, it’s not difficult to get around it: just navigate to /_layouts/15/savetmpl.aspx. But, wait, what if you get this?

image

Easy, easy. Open your site in SharePoint Designer, click Site Options:

image

and change the value of property SaveSiteAsTemplateEnabled from false to true:

image

And now you will be able to access savetmpl.aspx and save your site.

SharePoint Reference Document Updated

Just updated my SharePoint reference document Excel (references: here and here) with the default content placeholders.

It now contains:

  • Fields: all the built-in SharePoint field types;
  • Content types;
  • List templates;
  • Site templates;
  • SPDataSource returned fields;
  • List fields;
  • Document library fields;
  • Search content classes;
  • Content placeholders in default master pages.

If you have any corrections or if I missed something, please let me know!