ASP.NET Core Feature Flag TagHelper

Releasing stuff is dangerous: you might break things, you might annoy your users or you could screw up in any number of entertaining ways.

Feature flags are a great way to get functionality into production without quite so much risk. You can release your new feature to only a small subset of your users and then roll it out once you’re happy that things aren’t on fire.

The way you define flags will depend on the requirements for roll out – sometimes a configuration setting is sufficient; sometimes you’ll need per-user settings or something more complex. That’s outside the scope of this article though – I’ll leave that part up to you.

Once you have your flags defined you want to start modifying content based on those flags. You coulds do that with a bunch of if statements but when we’re talking about Razor it can get messy fast.

Instead, wouldn’t it be nice to wrap your new stuff in a special tag?

<feature flag="MyCoolNewThing">
  <!-- cool content here -->
</feature>

Or if you want to display something only for users without the new feature?

<feature flag="MyCoolNewThing" disabled>
  Click here to enable my new cool thing!
  <button>Enable Now!</button>
</feature>

Tag Helpers make this easy!

The TagHelper Class

Tag helpers allow you to write server-side code that manipulates the DOM during the render of a Razor view. They can accept dependency-injected services (in the scope of the current request) and can access attributes and child content of their Razor element.

They are implemented by extending the TagHelper class and are used in Razor views by converting the class name to a kebab-cased equivalent. e.g. MyGreatNewTagHelper would be available via the my-great-new tag.

The class then modifies the generated DOM by overriding either the Process or ProcessAsync methods. These methods are passed context objects to allow both interrogation of the current content and modification of the output.

public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
  //...
}

Hiding Child Content

In our case, the “modification” we want is really simple: we want to optionally hide all child content. This is directly supported via the TagHelperOutput.SuppressContent() method so we can hide content with a 1 line method:

public override async Task ProcessAsync(
  TagHelperContext context, 
  TagHelperOutput output)
{
  output.SuppressContent();
}

note that we don’t need to be using the ProcessAsync variant as we have no async code yet, but we’ll be adding some shortly

Optionally Hiding Child Content

We only want to hide the child content if a feature flag is disabled, so we need to know the state of the flag. There are a lot of ways that feature flag settings could be implemented (configuration settings, per-user flags, etc.) so we are going to abstract all of that away behind an interface:

public interface IFeatureFlagProvider {
  Task<bool> IsEnabled(FeatureFlag featureFlag);
}

public enunm FeatureFlag {
  Unknown,
  MyCoolNewThing,
  AnotherAwesomeFeature,
  Etc
}

The IFeatureFlagProvider accepts an enum value identifying a feature and asynchronously returns a boolean indicating whether or not the feature is enabled. Any complexity around how you determine the availability of the feature can happily hide behind this facade.

Note: I’m using an enum to define my features but strings are a valid alternative. I prefer enums because you can find all references easily and if you’re adding new features then you’re going to be changing code anyway!

As I said above, tag helpers can accept injected dependencies so as soon as we have registered an implementation of IFeatureFlagProvider we can use it in our helper. We’re also going to add a Flag property which will be set on each instance of the tag.

public class FeatureTagHelper : TagHelper
{
  private readonly IFeatureFlagProvider _featureFlagProvider;

  public FeatureTagHelper(IFeatureFlagProvider featureFlagProvider)
  {
    _featureFlagProvider = featureFlagProvider;
  }

  public FeatureFlag Flag { get; set; }

  public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
  {
    var isFeatureEnabled = await _featureFlagProvider.IsEnabled(this.Flag);
    if (!isFeatureEnabled)
      output.SuppressContent();
  }
}

Support Disabled State

We may want to show content only when a feature is not enabled (e.g. an “enable now” message) so we want to support the inverse. One option would be to create a second tag helper but I felt like a disabled flag made more sense when in Razor:

<feature flag="FeatureName" disabled>...</feature>

To achieve this we can use the supplied TagHelperContext to look for a disabled attribute and then combine this with our isFeatureEnabled condition from earlier:

public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
    var isFeatureEnabled = await _featureFlagProvider.IsEnabled(this.Flag);
    var isTagDisabled = context.AllAttributes.Where(a => a.Name?.ToLowerInvariant() == "disabled").Any();

    var showContent = isFeatureEnabled != isTagDisabled;
    if (!showContent)
      output.SuppressOutput();
  }
}

Using the TagHelper

Now that we’ve created the tag helper we can start using it in our Razor views.

Before it becomes available we will need to add it to the project in the Views/_ViewImports.cshtml file that is created as part of the ASP.NET Core templates.

You can either add all tag helpers in your project or add each one individually.

<!-- add all in assembly MyProject -->
@addTagHelper *, MyProject
<!-- or add individually -->
@addTagHelper MyProject.TagHelpers.FeatureTagHelper, MyProject

Once that’s done you can use the new tags in any of your Razor pages or views as below:

<feature flag="MyCoolNewThing">
  <!--
    content will only be displayed if FeatureFlag.MyCoolNewThing is enabled
    for the current user
  -->
  <h1>Cool New Thing</h1>
</feature>

<feature flag="MyCoolNewThing" disabled>
  <!--
    content will only be displayed if FeatureFlag.MyCoolNewThing is disabled
    for the current user
  -->
  Click here to enable my new cool thing!
  <button>Enable Now!</button>
</feature>
Advertisements

Lightweight Bar Chart in Vanilla CSS

There are a hundred and one JavaScript charting libraries out there that can do amazing things with your data. Sometimes, though, a whole library is overkill. Libraries come at a cost and for simple charts you can often do what you need without any third party code at all.

Here’s an example of how you can create a bar chart using just HTML and CSS.

The HTML

First off we’ll need some HTML to manipulate with our CSS. You’ll probably be using server side rendering and for this example I was using Razor pages. My .cshtml looked
something like this:

<div class="chart">
  <div class="bars">
    @foreach (var point in Model.Data)
    {
    <div class="bar" style="height:@(point.ValueAsPercentOfMax)%;"></div>
    }
  </div>
  <div class="labels">
    @foreach (var point in Model.Data)
    {
    <span class="label">@point.Label</span>
    }
  </div>
</div>

…which outputs HTML like this…

<div class="chart">
  <div class="bars">
    <div class="bar" style="height:50%;"></div>
    <div class="bar" style="height:20%;"></div>
    <div class="bar" style="height:70%;"></div>
    <!-- etc -->
  </div>
  <div class="labels">
    <span class="label">Bar 1</span>
    <span class="label">Bar 2</span>
    <span class="label">Bar 3</span>
    <!-- etc -->
  </div>
</div>

One important thing to note is that we are translating our data values into %age heights on the .bar divs. Combined with some CSS this will turn these divs into the bars in our bar chart.

That’s all we need to do for the DOM but so far it doesn’t look great

plain-dom

Let’s add some styles!

The CSS

First things first: we need to be able to see the bars. At the moment the .bar divs have a %age height set but their containing element .bars has zero height. A %age of zero is zero, so no bars!

We want the bars to take up all available space above the labels so let’s turn .chart into a vertical flexbox and set the .bars to flex so they fill up anything left over from the labels.

Note: I’ve given the chart a fixed height & width, but we’ll be writing this so that it will grow or shrink to fit the available space. I’ve also given each .bar a background color so we can see where they are!

.chart {
  height: 100px;
  width: 200px;
  display: flex;
  flex-direction: column;
}

.bars {
  flex: 1;
}

.bar {
  background: red;
}

bar-height

Now the .bars container is the right height (pushing the labels to the bottom) but we still can’t see them. This time they have height but zero width.

We can get .bars to space it’s components out horizontally, then have each .bar grow to take up the available space with flex: 1. By setting all child elements of .bars to have the same flex value they will all be assigned the same share of the available space.

.bars {
  flex: 1;
  display: flex;
  flex-direction: row;
}
.bar {
  flex: 1;
  background: red;
}

horizontal-spacing

Ok, now we’re getting somewhere: we have bars! We don’t want them at the top though, so let’s set .bars to align it’s items to flex-end to get them to the bottom.

.bars {
  /* ...as above... */
  align-items: flex-end;
}

vertical-align

Better. Those labels need to line up with the columns though, so let’s apply the same horizontal flex to .labels-container. We can add some text alignment and a little padding while we’re about it.

.labels {
  display: flex;
  flex-direction: row;
}
.label {
  flex: 1;
  padding: 3px;
  text-align: center;
}

labels

Much better, but the “big red square” column style isn’t the best. Let’s give each column some padding, border and a nice background color and…

.bar {
  flex: 1;
  border-radius: 3px 3px 0 0;
  background: rgba(98, 144, 200, 1);
  border: 1px solid rgba(55, 105, 150, 1);
  border-bottom: none;
  margin: 0 18px;
}

pretty-bars

Pretty good! We just want one final touch to add a bit of polish: animation. We can make our bars grow to their full height as the page loads by animating the translateY property from 100% (i.e. entirely outside the parent element) to 0 (i.e. the desired final position).

@keyframes grow-column {
  0% {
    transform: translateY(100%);
  }
  100% {
    transform: translateY(0);
  }
}

.bars {
  /* ...as above ... */
  overflow: hidden;
}

.bar {
  /* ... as above ... */
  animation: grow-column 1s;
}

We need to set the containing .bars element to hide all overflow content; otherwise we would see the columns sliding in over the top of the labels.

animation

✨ tada! ✨ A nice looking simple bar chart at a cost of a few bytes of CSS!

Composite Pattern in .NET Core with Dependency Injection

Following on from my previous post where I implemented a decorator pattern using .NET Core dependency injection I realised that I could use the same method to create a composite pattern in a developer-friendly way.

Composite Pattern

Similar to the decorator pattern, the Composite Pattern let’s you wrap existing implementations of an interface to augment the functionality.

The difference between the two is that the decorator wraps a single instance of the interface; a composite wraps many.

interface IService {
  void DoSomething(string value);
}

class Decorator : IService {
  public Decorator(IService wrappedService) {
    //...
  }
}

class Composite : IService {
  public Composite(IEnumerable<IService> wrappedServices) {
    //...
  }
}

This is useful where you have a number of implementations of your service and you don’t want dependent classes to know whether they should call one, some or all of them.

For example, if you have a report generator that wants to send results to multiple sources you might implement several instances of IReporter:

interface IReporter {
  void Send(IReport report);
}

class ConsoleReporter : IReporter {
  public void Send(IReport report) {
    //write details to console
  }
}

class TelemetryReporter : IReporter {
  public void Send(IReport report) {
    //write stats to a telemetry service
  }
}

class EmailReporter : IReporter {
  public void Send(IReport report) {
    //send a report email to stakeholders
  }
}

Your composite reporter would construct on all other implementations of IReporter and call them in order:

class CompositeReporter : IReporter {
  private IEnumerable<IReporter> _reporters;

  public CompositeReporter(IEnumerable<IReporter> reporters) {
    _reporters = reporters;
  }

  public void Send(IReport report) {
    foreach (var reporter in _reporters)
      reporter.Send(report);
  }
}

This means that anything that needs to send a report can request a single IReporter and let the CompositeReporter worry about routing the report through the correct concrete implementations.

Default DI Behaviour

As discussed in the previous post, the default behaviour of the .NET Core Dependency Injection framework is to provide the last-registered copy of an interface, or all registered copies for an IEnumerable.

services.AddScoped<IService, ConcreteService1>();
services.AddScoped<IService, ConcreteService2>();
services.AddScoped<IService, ConcreteService3>();

//later
const service = serviceProvider.GetRequiredService<IService>();
// service is instance of ConcreteService3

const allServices = serviceProvider.GetRequiredService<IEnumerable<IService>>();
// allServices contains one instance of all 3 registered implementations

What we need is a way to register a new type to replace the existing registrations and take them in as a constructor dependency.

class Composite : IService {
  public class Composite(IEnumerable<IService> services) {
    //...
  }
}

//BAD - throws StackOverflowException when resolved!
services.AddScoped<IService, Composite>();

Unfortunately the default behaviour of the DI framework is to attempt to fulfil the request for all IService implementations with…another instance of Composite! One StackOverflowException later and we’re back to the drawing board.

How can we make this play nicely with DI?

Borrowing from the Last Post

After some digging through the ASP.NET Core source code in the last post we came up with a couple of useful helpers that we can re-use here: CreateFactory and CreateInstance.

ActivatorUtilities.CreateFactory generates a factory function to create an instance of ConcreteType from the service provider with some services provided explicitly.

var objectFactory = ActivatorUtilities.CreateFactory(
  typeof(ConcreteType), 
  new[] { typeof(IService) });

CreateInstance creates an instance of a service from a ServiceDescriptor.
We can get instances of ServiceDescriptor from the service collection and use these to create previously-registered types.

public static object CreateInstance(this IServiceProvider services, ServiceDescriptor descriptor)
{
  if (descriptor.ImplementationInstance != null)
    return descriptor.ImplementationInstance;

  if (descriptor.ImplementationFactory != null)
    return descriptor.ImplementationFactory(services);

  return ActivatorUtilities.GetServiceOrCreateInstance(services, descriptor.ImplementationType);
}

With these tools we can define our desired composite behaviour.

Extract Existing Registrations

When we register a new composite we want to

  1. Remove all existing registered services for the same interface
  2. Insert the composite implementation
  3. Pass instances of all removed implementations into the constructor of the composite

Remove Existing Registrations

IServiceCollection extends IEnumerable so we can filter it down to get the services that match the interface of the composite class.

public static void AddComposite<TInterface, TConcrete>(this IServiceCollection services)
  where TInterface : class
  where TConcrete : class, TInterface
{
  //get a list of existing registrations matching the target interface
  var wrappedDescriptors = services
    .Where(s => s.ServiceType == typeof(TInterface))
    .ToList();

  //remove each from the service collection
  foreach (var descriptor in wrappedDescriptors)
    services.Remove(descriptor);

  //...
}

We call ToList to we get a persistent list of the items and then remove them from the original collection.

Add Composite Implementation

Next up we want to insert the definition of our composite class, and we’re going to use the ActivatorUtilites helper mentioned above.

var objectFactory = ActivatorUtilities.CreateFactory(
  typeof(TConcrete),
  new[] {
    typeof(IEnumerable<TInterface>)
  });

Here we create a factory function that can be used with a service provider to resolve an instance of TConcrete (i.e. our composite class) with any parameters of type IEnumerable{TInterface} manually specified by us.

The objectFactory forms the basis of a new ServiceDescriptor to add to the collection.

var compositeDescriptor = ServiceDescriptor.Describe(
  typeof(TInterface),
  serviceProvider => (TInterface)objectFactory(serviceProvider, new [] {
    /* todo: inject original services here */
  },
  ServiceLifetime.Scoped);
);

services.Add(compositeDescriptor);

Note: in this example I have hard-coded a lifetime of Scoped for the service. We can improve on this below but it will do for now.

Inject Original Services

We still need to inject instances of the original services that we removed. We recorded their service descriptors in wrappedDescriptors and we can now combine those with the CreateInstance extension method above to populate our constructor parameter.

var compositeDescriptor = ServiceDescriptor.Describe(
  typeof(TInterface),
  serviceProvider => (TInterface)objectFactory(serviceProvider, new [] {
    wrappedDescriptors
      .Select(d => serviceProvider.CreateInstance(d))
      .Cast<TInterface>()
  },
  ServiceLifetime.Scoped);
);

Now all of the wrapped services will be created through the service provider and passed to our composite.

This approach may seem long winded but it has the advantage that any other dependencies of either the wrapped services or our composite will also be injected from the service provider with no further input from us!

Calculate Lifetime Scope

The hard-coded lifetime scope isn’t ideal, and whilst we could push the onus onto the caller to specify a scope we can do slightly better and infer it from the existing registrations.

If the composite depends on a Scoped instance then it can be either Scoped or Transient without a problem, but cannot be Singleton as it would not have access to scoped dependencies.

We can infer the maximum scope of the composite by taking the most specific scope of it’s dependencies. The ServiceLifetime enum is defined with the least specific scope (Singleton) as 0 so we can select the maximum value to get the most specific.

Pull it All Together

Combining all of the above we get the following extension method:

public static void AddComposite<TInterface, TConcrete>(this IServiceCollection services)
  where TInterface : class
  where TConcrete : class, TInterface
{
  var wrappedDescriptors = services.Where(s => s.ServiceType == typeof(TInterface)).ToList();
  foreach (var descriptor in wrappedDescriptors)
    services.Remove(descriptor);

  var objectFactory = ActivatorUtilities.CreateFactory(
    typeof(TConcrete), 
    new[] { typeof(IEnumerable<TInterface>) });

  services.Add(ServiceDescriptor.Describe(
    typeof(TInterface),
    s => (TInterface)objectFactory(s, new[] { wrappedDescriptors.Select(d => s.CreateInstance(d)).Cast<TInterface>() }),
    wrappedDescriptors.Select(d => d.Lifetime).Max())
  );
}

Now we can wrap up as many services as we want in a composite with one line

var services = new ServiceCollection();
services.AddSingleton<IReporter, ConsoleReporter>();
services.AddScoped<IReporter, TelemetryReporter>();
services.AddTransient<IReporter, EmailReporter>();

services.AddComposite<IReporter, CompositeReporter>();

Post-Logout Redirect with ASP.NET Core and ADFS 2016

Redirect after logout

When a user logs out from your app you have the option to log them out of the provider as well by redirecting the browser to the logout endpoint. By default this means that the user will end up sat on your providers “You have signed out” page – not brilliant.

You can, however, tell your provider to redirect back to your app once they’re done with logout by specifying a post_logout_redirect_uri.

For ASP.NET Core Identity you can specify this redirection as a parameter on the SignOutResult.

[Route("auth")]
public class AuthController
{
  [HttpPost("logout")]
  public IActionResult Logout() => new SignOutResult(
    OpenIdConnectDefaults.AuthenticationScheme,
    new AuthenticationProperties { RedirectUri = Url.Action(nameof(LogoutSuccess))});

  [HttpGet("logoutSuccess")]
  public IActionResult LogoutSuccess() => View();
}

Useless ADFS error messages

For ADFS 2016 you need to do a little bit more than just set the redirect URL. On first inspection you can see that the above will set the parameter in the ADFS URL but ADFS will silently ignore it and your user will sit forever on the ADFS sign-out page.

Digging into the event logs you will find the following error message:

The specified redirect URL did not match any of the OAuth client’s redirect URIs. The logout was successful but the client will not be redirected

If you’re unlucky, this wonderfully-misleading error message can take you down a rabbit hole of further configuration. It’s a shame, then, that no-one thought to expose something a little more accurate:

That redirect looks good but you need to specify id_token_hint or we’ll ignore you

Thanks ADFS!

Sending ID Token Hint

To be fair to ADFS, sending an id_token_hint is recommended by the spec. This parameter needs to be set to the id_token that was sent to your app when the user first logged in; provide this value and ADFS will happily redirect back to your app.

The only problem here is that you probably don’t still have that id_token. ASP.NET Core Identity uses the identity information to create an auth cookie and then (by default) discards it.

Happily, the OpenIdConnectOptions exposes a SaveTokens property to persist the received token to the auth cookie. Even better: the OIDC logout mechanism will automatically pick this up once enabled so you should be good to go as soon as you set the flag:

public class Startup {
  public void ConfigureServices(IServiceCollection services)
  {
    services.AddAuthentication()
      .AddOpenIdConnect(options => {
        options.SaveTokens = true;
        //...set other options
      });

    //...other service config
  }
}

This does have one important downside though: you’re now storing much more information in your auth cookie and that adds extra data to every client request, maybe even doubling the cookie size.

Whether or not this is a problem for your app is another decision – at least your logout redirect works now!

Generic behaviour in ASP.NET Core with Action Filters

Everyone hates copy/pasting code, and Action Filters in ASP.NET Core MVC offer a great way to avoid filling your controllers with boilerplate.

Filters offer you entry points into the execution pipeline for an action where you can examine the incoming parameters or generated results and modify them to suit your needs.

Here are a couple of examples of how this can help.

Treat a null result as a 404 Not Found

By default an ASP.NET Core controller will return a 204 No Content response if you return null from an action:

[Route("api/example")]
public class ExampleApiController : Controller
{
  [HttpGet("")]
  public string GetExample()
  {
    return null;
  }
}

In some cases, however, you might not want to treat null as No Content. If your API is looking up a resource by ID, for example, then a 404 Not Found response would be more useful:

[HttpGet("{id}")]
public MyDtoObject GetById(int id)
{
  if (!_store.ContainsId(id))
    return null; //should return 404

  //...
}

We can use an action filter to automatically replace the null result with a NotFoundResult:

//filter
public class NullAsNotFoundAttribute : ActionFilterAttribute
{
  public override void OnActionExecuted(ActionExecutedContext context)
  {
    var objectResult = context.Result as ObjectResult;

    if (objectResult?.Value == null)
      context.Result = new NotFoundResult();
  }
}

//controller
[HttpGet("{id}")]
[NullAsNotFound]
public MyDtoObject GetById(int id)
{
  //...
}

Here we override OnActionExecuted to invoke our code after the action method has generated a result but before that result is processed.

If the generated result is an ObjectResult with a null value then we replace it with an empty NotFoundResult and our controller will now return a 404 response.

Treat invalid models as a 400 Bad Request

It is very common to see the following pattern in MVC controllers:

[HttpPost("")]
public IActionResult Create(MyModel model)
{
  if (!ModelState.IsValid)
    return new BadRequestObjectResult(ModelState); //or a View, or other validation behaviour

  //...eventually return created model
  return Ok(model);
}

This has 2 downsides:
* Boilerplate code in every action that needs to validate
* Return type must be IActionResult to accomodate 2 result types

The second point is fairly minor but worth noting. By exposing IActionResult instead of the concrete type we lose metadata about the action.
That metadata is useful for things like generating swagger docs, and losing it can mean you need to decorate the method with response types (though this is improved in ASP.NET Core 2.1 with IActionResult).

In any case, we can make this behaviour generic by moving the validation check into another action filter:

public class InvalidModelAsBadRequestAttribute : ActionFilterAttribute
{
  public override void OnActionExecuting(ActionExecutingContext context)
  {
    if (!context.ModelState.IsValid)
      context.Result = new BadRequestObjectResult(context.ModelState);
  }
}

This time we are overriding OnActionExecuting instead of OnActionExecuted so our code gets run before the controller action. We can tell if the model is invalid before hitting our controller so we can skip the action entirely if we know it should be replaced with a 400.

Other Possibilities

Wherever you find yourself writing duplicate code in many actions it is worth considering whether it can be pulled out into a filter (or middleware) to keep your controllers clean and focussed on their intent.

Supporting SignalR Client Handlers after Connection Start

(Yes, that is a pretty specific post title but then this is a pretty specific problem…)

In general, when you create a new SignalR connection you are obliged to have already defined any of your handlers on the connection.yourHubName.client object. This allows SignalR to discover those handlers and hook them up to the incoming messages.

Problem: Multiple connection sources

This approach is fine as long as you have a single place from which you are starting your connection but what if you have 2 hubs, 2 separate client handlers…2 of everything?

They will both automatically share a SignalR connection so you can end up with a bit of a race condition where the first handler to start the connection will be the only handler registered.  Imagine the following handlers…

function MyFirstHandler() {
  //assign the handler
  $.connection.myHub1.client.method1= function() { ... };

  //start the connection
  $.connection.myHub1.connection.start();
}

function MySecondHandler() {
  //assign the handler
  $.connection.myHub2.client.method2= function() { ... };

  //start the connection
  $.connection.myHub2.connection.start();
}

//...some time later...
new MyFirstHandler()
//...and even later still...
new MySecondHandler()

By the time we create MySecondHandler we have already created the connection and so method2 is not attached and will never be invoked.

Solution: Proxy implementation

We can work around this by replacing the connection.yourHubName.client object (normally just a POJO) with something that is aware of the available server methods.  The new client then exposes stubs to which SignalR can connect before our MySecondHandler can provide the “real” handler implementations.

//before creating any handlers
$.connection.myHub1.client = new SignalRClient(['method1','otherHandler']);
$.connection.myHub2.client = new SignalRClient(['method2']);

The SignalRClient implementation has 3 requirements for each named handler:

  1. Always return a valid handler function for SignalR to bind, even if the real handler hasn’t been assigned yet
  2. If the real handler has been assigned, invoke that when the handler is invoked (with all args etc.)
  3. Allow client.myHandler = function(){} assignments for compatibility with existing code

The last requirement means that we need to use Object.defineProperty with custom getter and setter implementations.  The getter should always return a stub method; the setter should store the real handler; and the stub method should invoke the real handler (if assigned).

function SignalRClient(methods) {
	this._handlers = {};
	methods.forEach(this.registerHandler.bind(this));
}

SignalRClient.prototype.invokeHandler = function(name) {
	var handler = this._handlers[name];
	if (handler) {
		var handlerArgs = Array.prototype.slice.call(arguments, 1);
		handler.apply(this, handlerArgs);
	}
}

SignalRClient.prototype.registerHandler = function(name) {
	var getter = this.invokeHandler.bind(this, name);
	Object.defineProperty(this, name, {
		enumerable: true,
		get: function() { return getter },
		set: function (value) { this._handlers[name] = value; }.bind(this)
	});
}

Note that our defined properties must also be marked as enumerable so that the SignalR code picks up on them when it attempts to enumerate the client handler methods.

Now – provided we know the available methods up front – we can start the connection whenever we like and assign our handlers later!

Custom Operation Names with Swashbuckle 5.0

This is a post about Swashbuckle –  a .NET library that seamlessly adds Swagger support to WebAPI projects.  If you aren’t familiar with Swashbuckle then stop reading right now and go look into it – it’s awesome.

library-api

Swashbuckle has recently released version 5.0 which includes (among other things) a ridiculous array of ways to customise your generated swagger spec.

One such customisation point allows you to change the operationId (and other properties) manually against each operation once the auto-generator has done it’s thing.

Why Bother?

Good question.  For me, I decided to bother for one very specific reason: swagger-js.  This library can auto-generate a nice accessor object based on any valid swagger specification with almost no effort, whilst doing lots of useful things like handling authorization and parsing responses.

swagger-js uses the operationId property for method names and the default ones coming out of Swashbuckle weren’t really clear or consistent enough.

Injecting an Operation Filter

The means for customising operations lies with the IOperationFilter interface exposed by Swashbuckle.

public interface IOperationFilter
{
  void Apply(Operation operation, 
    SchemaRegistry schemaRegistry, 
    ApiDescription apiDescription);
}

When implemented and plugged-in (see below), the Apply method will be called for each operation located by Swashbuckle and allows you to mess around with its properties.  We have a very specific task in mind so we can create a SwaggerOperationNameFilter class for our purpose:

public class SwaggerOperationNameFilter : IOperationFilter
{
  public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
  {
    operation.operationId = "???";
  }
}

When you installed the Swashbuckle nuget package it will have created a SwaggerConfig file in your App_Start folder.  In this file you will likely have a long and well-commented explanation of all available configuration points, but to keep things simple we can insert the reference to our filter at the end:

GlobalConfiguration.Configuration
  .EnableSwagger(c =>
  {
    //...
    c.OperationFilter<SwaggerOperationNameFilter>();
  });

Getting the Name

At this point you have a lot of flexibility in how you generate the name for the operation.  The parameters passed in to the Apply method give you access to a lot of contextual information but in my case I wanted to manually specify the name of each operation using a custom attribute.

The custom attribute itself contains a single OperationId property…

[AttributeUsage(AttributeTargets.Method)]
public sealed class SwaggerOperationAttribute : Attribute
{
  public SwaggerOperationAttribute(string operationId)
  {
    this.OperationId = operationId;
  }

  public string OperationId { get; private set; }
}

…and can be dropped onto any action method as required…

[SwaggerOperation("myCustomName")]
public async Task<HttpResponseMessage> MyAction()
{
  //…
}

Once the attributes are in place we can pull the name from our filter using the ActionDescriptor

operation.operationId = apiDescription.ActionDescriptor
  .GetCustomAttributes<SwaggerOperationAttribute>()
  .Select(a => a.OperationId)
  .FirstOrDefault();

Voila!