This is step 10 of my blog series on Web Application Development in Fsharp using ASP.NET MVC

In the fsharp-phonecat application that we are creating as part of this series, to create the controller instances, we are using Pure DI. Though this composition root solves the problem of dependency injection, the quality of the code is not up to the mark.

In this blog post we are going to refactor this and make it shorter and more F# idiomatic.

The current state of GetControllerInstance method

It’s if full of if..else if.. else if.. else and the method is too long

As depicted in the above screenshot, the GetControllerInstance method does the following three things for all the controller types in the application

Checks the incoming controller type

Creates the requested controller instance

Returns the created controller instance

This can be refactored to a function

The function takes a type and returns an Option type of IController

Let’s do the same for an another controller creation which is little complex than this.

Here in this case to create an instance of PhoneController we need two additional parameters, Phones sequence and anonymous id of the session.

With these functions in place, the GetControllerInstance method would look like as below

Though the functions that have created has reduced the size of the method, it has introduced an another problem (Pyramid Of Doom) as indicated by the arrow in the screenshot.

We can get rid of this using a bind function as we did in validation step using rop.

The downside of the bind function is it’s not generic and we can’t reuse the existing bind function that we have created for doing validation.

So, going with this approach would lead to adding more code which is not in alignment with the objective of this refactoring.

What can we do ??

The answer is Active Patterns

Active Patterns allow programmers to wrap arbitrary values in a union-like data structure for easy pattern matching. For example, its possible wrap objects with an active pattern, so that you can use objects in pattern matching as easily as any other union type - F# Programming WikiBook

We are going to use Partial Active Patterns to refactor the composition root.

Creating Partial Active Patterns

Let’s start by creating a partial active pattern for HomeController

As described in the screenshot, it’s very similar to the createHomeController function and the only difference is the addition of the Banana Clips (yellow ellipses). The _ symbol makes the active pattern partial.

The partial active patterns always returns an Option type.

Partial active patterns support defining pattern with multiple parameters. So we can change the createPhoneController function as below

Great! We are almost done with the refactoring. The pending step is leveraging these partial active patterns in the GetControllerInstance method.

It’s where the beauty of pattern matching reveals!

What’s happening here?

Based on the Active Pattern Name ( HomeController ), the control goes to the corresponding active pattern

), the control goes to the corresponding active pattern The value we are matching ( controllerType ) passed as argument.

) passed as argument. The value returned by the active pattern (instance of HomeController ) is assigned to the homeController literal in the match expression

) is assigned to the literal in the match expression If none of the pattern has met the matching criteria, it executes the default match (raising the exception)

It does the same thing for the Active Patterns with multiple parameters

The only thing to note here is, the value against which we are matching is always passed as a last argument.

That’s it!!

After completing the creation of partial active patterns for all the other controller types in the application, the GetControllerInstance would be shorter like this

Summary

Moving from C# to F#, it’s not just change in syntax! It’s much more than that. The perfect analogy for this refactoring is the classic proverb When in Rome, do as the Romans do. You can find the complete source code of this step in the phonecat github repository