C# Corner

Fluent Interface Design in .NET

Eric Vogel shows you how to simplify the consumption of your API by adding a fluent interface design.

One way to clean up an existing API is to provide a fluent interface to it. The goal of a fluent interface is to simplify the consumption of your API by making it more readable and discoverable.

If you have a class library for sending an email message, a non-fluent version of the library entails constructing an email sender that connects to an outgoing mail server with a set of user credentials. Then you create an email that contains a message-to and message-from address along with the message body. Finally, you pass the email message to the sender object for delivery. The following example shows a non-fluent email API:

var sender = new EmailSender("smtp.emailserver.com");
sender.SetCredentials("username","password");
var emailMessage = new EmailMessage();
message.To = "[email protected]";
message.From = "[email protected]";
message.Message = "Hello from the world of tomorrow!";
sender.Send(message);

The code for such a library consists of an EmailSender class, shown in Listing 1, and an EmailMessage class, shown in Listing 2.

If you were to describe the flow of the program, you might say: Send a new email message from my account to [email protected] saying, "Hello from the world of tomorrow!" with the subject, "hello."

Here's a fluent version of the same API:

new
EmailSender().FromServer("smtp.emailserver.com").WithCredentials(username:"username",password:
"password").CreateEmail().From("[email protected]").To("[email protected]").Saying("Hello from
the world of tomorrow!").WithSubject("Hello").Done().Send();

Implementing the Fluent Interface
Now that I've defined how the Fluent API will function, I'll go over how to implement it. First, I'll define the IFluentEmailSender interface that allows the EmailSender to be accessed in a fluid manner. The FromServer and WithCredentials methods both return the interface itself, which allows the methods to be called in either order. The CreateEmail message method returns an implementer of the IFluentEmailMessage interface to allow the email message to be defined. The Send method is used to deliver the email. The full interface source code is shown in the following example:

using System;
 
namespace VSMFluentInterfaces.Fluent
{
    public interface IFluentEmailSender
    {
        IFluentEmailSender FromServer(string host);
        IFluentEmailSender WithCredentials(string username, string password);
        IFluentEmailMessage CreateEmail();
        void Send();
    }
}

Next you define the IFluentEmailMessage interface that will allow setting of properties on an email message. Each method on the interface, except Done, will return the interface itself to allow method chaining. In this way, a user of the interface may call any of the methods, except Done, in any order. The Done method is the terminating method, which returns the IFluentEmailSender interface instance, so the email message may be sent. The following code shows the IFluentEmailMessage for the full interface definition:

using System;
 
namespace VSMFluentInterfaces.Fluent
{
    public interface IFluentEmailMessage
    {
        IFluentEmailMessage From(string fromAddress);
        IFluentEmailMessage To(string toAddress);
        IFluentEmailMessage Saying(string message);
        IFluentEmailMessage WithSubject(string subject);
        IFluentEmailSender Done();
    }
}

Now you add the Fluent interface to the EmailSender and EmailMessage classes. I've chosen to go with a partial class implementation. This approach allows the existing code to remain mostly untouched, and the Fluent implementation to remain isolated from the core classes.

First you update the EmailSender class. Create a new partial class file named EmailSender.Fluent.cs.

Next, implement the IFluentEmailSender interface. The FromServer method sets the outgoing email host address and returns the class itself. The WithCredentials method calls the existing SetCredentials method, passing the username and password, and returns itself. The CreateEmail method creates a new EmailMessage object and returns it. The Send method simply calls the existing Send method with the created EmailMessage object. See Listing 3 for the full EmailSender fluent API implementation.

Now you update the EmailMessage class to implement the IFluentEmailMessage interface. Add a new class file named EmailMessage.Fluent.cs. I've added an IFluentEmailSender private member variable that is used for the Done method implementation. The methods--From, To, Saying, and WithSubject--each set the appropriate property on the object instance and return the object itself. The Done method returns the IFluentEmailSender member that is set in the object constructor, which allows the email to be sent by the sender. See Listing 4 for the full EmailMessage Fluent API implementation.

As you can see, by adding a fluent interface to an existing API, you can increase its ease of use. In addition, the API consumer code becomes more readable and discoverable.

As with all patterns, there's the downside of added code complexity. If your existing API is already small, or very simple, then adding a fluent interface may not be worth it. On the other hand, if your existing API is cumbersome to use, or you're creating a new API, consider adding a fluent interface and reap its benefits.

About the Author

Eric Vogel is a Senior Software Developer for Red Cedar Solutions Group in Okemos, Michigan. He is the president of the Greater Lansing User Group for .NET. Eric enjoys learning about software architecture and craftsmanship, and is always looking for ways to create more robust and testable applications. Contact him at [email protected].

comments powered by Disqus

Featured

  • AI for GitHub Collaboration? Maybe Not So Much

    No doubt GitHub Copilot has been a boon for developers, but AI might not be the best tool for collaboration, according to developers weighing in on a recent social media post from the GitHub team.

  • Visual Studio 2022 Getting VS Code 'Command Palette' Equivalent

    As any Visual Studio Code user knows, the editor's command palette is a powerful tool for getting things done quickly, without having to navigate through menus and dialogs. Now, we learn how an equivalent is coming for Microsoft's flagship Visual Studio IDE, invoked by the same familiar Ctrl+Shift+P keyboard shortcut.

  • .NET 9 Preview 3: 'I've Been Waiting 9 Years for This API!'

    Microsoft's third preview of .NET 9 sees a lot of minor tweaks and fixes with no earth-shaking new functionality, but little things can be important to individual developers.

  • Data Anomaly Detection Using a Neural Autoencoder with C#

    Dr. James McCaffrey of Microsoft Research tackles the process of examining a set of source data to find data items that are different in some way from the majority of the source items.

  • What's New for Python, Java in Visual Studio Code

    Microsoft announced March 2024 updates to its Python and Java extensions for Visual Studio Code, the open source-based, cross-platform code editor that has repeatedly been named the No. 1 tool in major development surveys.

Subscribe on YouTube