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");
var emailMessage = new EmailMessage();
message.To = "[email protected]";
message.From = "[email protected]";
message.Message = "Hello from the world of tomorrow!";

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:

"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


  • Top 3 Blazor Extensions for Visual Studio Code

    Some developers prefer to create applications with Microsoft's open-source Blazor tooling from within the open-source, cross-platform Visual Studio Code editor. Here are the top tools in the VS Code Marketplace for those folk, as measured by the number of installations.

  • How to Invert a Machine Learning Matrix Using C#

    VSM Senior Technical Editor Dr. James McCaffrey, of Microsoft Research, explains why inverting a matrix -- one of the more common tasks in data science and machine learning -- is difficult and presents code that you can use as-is, or as a starting point for custom matrix inversion scenarios.

  • Microsoft Engineer: 'It's Time to Move OData to .NET 5'

    Microsoft engineer Sam Xu says "it’s time to move OData to .NET 5" and in a new blog post he shows how to do just that.

  • Microsoft Goes Virtual with Developer Education in Face of COVID-19

    Like many organizations that host developer educational events, Microsoft has gone virtual amid shelter-in-place directives and a surge in remote work stemming from the COVID-19 pandemic.

  • Microsoft Enhances Low-Code Power Apps

    Microsoft's nod to the low-code movement, Power Apps, has been enhanced with a bevy of new features, including mixed reality, canvas/model support in a new mobile app, UX improvements and more.

.NET Insight

Sign up for our newsletter.

Terms and Privacy Policy consent

I agree to this site's Privacy Policy.

Upcoming Events