ASP.NET Core 5.0 : MVC, Razor Pages, Web API, EF Core, Blazor, Design Patterns, and more. Private online coaching for software developers. Click here for more details.

Fluent interface and method chaining in C# for beginners

As a C# developer you expose functionality using classes and objects. Many a times the code required to accomplish a task using these classes and objects tends to be complex. In an attempt to reduce this complexity you might want to device a technique that makes your code more readable and natural. That is where Fluent Interface and Method Chaining can be useful. The remainder of this article discusses these techniques with simple examples. My aim is to quickly introduce you to these concepts. So, the examples are kept simple rather than building a full-fledge example.

Fluent interface and method chaining

Object oriented systems often involve a lot of classes and objects. To accomplish a specific task these classes and objects are utilized in a certain way. At times this consumption of classes and objects introduces complexity. Fluent interface is a technique that helps you reduce this complexity by creating a "domain specific language" consisting of several methods. Fluent interface also makes your code more readable and natural because it uses method chaining.

Method chaining is a technique where one method is called directly on another method forming a chain like structure. Consider the following example.

var emp = new Employee()
          .SetBasicDetails(1,"Nancy","Davolio")
          .SetSalaryDetails(20000)
          .SetProjectDetails("PROJ1",DateTime.Now);

Suppose you have the Employee class with three methods namely SetBasicDetails(), SetSalaryDetails(), and SetProjectDetails(). The above code creates an Employee object using the new keyworkd of C#. Then SetBasicDetails() method is called on that object in order to set basic details such as employee ID, first name, and last name. The SetBasicDetails() method is supposed to be returning an Employee object. The second method - SetSalaryDetails() - is directly called on this returned object thus forming a chain. On the same lines SetSalaryDetails() is supposed to return the Employee object and SetProjectDetails() method is invoked on it thus continuing the chain.

Note that the fluent interface and method chaining are not the same things. Fluent interface is a concept and method chaining is a way to implement it. In the above example, SetBasicDetails(), SetSalaryDetails(), and SetProjectDetails() form the domain specific language.

Method chaining simply means that the return value from one method is used to invoke the next method in the chain. Fluent interface requires that the methods participating in the chain return the same object (or context) to the next method in the chain.

If you have worked with LINQ, EF Core Fluent API, or ASP.NET Core's Startup class, chances are you have already used method chaining. Consider the following LINQ code:

List<Employee> list = new List<Employee>();
...
...
var data = list.Where(e => e.Country == "USA")
               .OrderBy(e => e.EmployeeID)
               .ToList();

The above code creates a List of Employee objects and stores certain employees (not shown in the code) in it. Then a LINQ query picks employees matching certain condition. Notice how various aspects of the LINQ query such as a WHERE condition and an ORDER BY clause are handled using method chaining. The terminating method ToList() ends the chain by returning the final list of employees (after applying the previous conditions).

The following example shows ConfigureServices() method from ASP.NET Core Startup class.

services.AddRazorPages()
        .AddRazorPagesOptions(...);

As you can see, AddRazorPages() method returns IMvcBuilder. So, the same context is passed to the AddRazorPagesOptions() method chained to it. The AddRazorPagesOptions() method also returns IMvcBuilder so that further methods in the chain (if any) can use it.

Finally, consider the following EF Core Fluent API code fragment.

modelBuilder.Entity()
            .Property(e => e.EmployeeID)
            .HasColumnName("EmployeeID")
            .HasDefaultValue(0)
            .IsRequired();

Here, Property(), HasColumnName(), HasDefaultValue(), and IsRequired() form the method chain and the same context is passed between the calls.

Now that you have some idea about fluent interface and method chaining, let's see a few simple examples of implementing them in C# code.

Example 1 - Performing CRUD operations

Suppose that you want to perform CRUD operations on a table. To accomplish this task you can create a class and the required methods. Consider the following code that shows one such implementation.

var crud = new CrudOnTable("Employees");
crud.Insert("Nancy Davolio");
crud.Update(1, "Andrew Fuller");
crud.Delete(3);
crud.Select(1, out data);

This code doesn't use method chaining and invokes Insert(), Update(), Delete(), and Select() methods as independent lines of code.

If you want to support method chaining you need to design your CrudOnTable class in a specific way. Let's see how that can be done.

public class CrudOnTable
{
    public CrudOnTable(string table)
    {
        ...
    }

    public CrudOnTable Insert(string data)
    {
        ...
        return this;
    }


    public CrudOnTable Update(int id, string data)
    {
        ...
        return this;
    }


    public CrudOnTable Delete(int id)
    {
        ...
        return this;
    }


    public CrudOnTable Select(int id, out string data)
    {
        ...
        return this;
    }
}

The above code shows the CrudOnTable class with a constructor and four methods.

The constructor accepts a name of the table on which CRUD operations are to be performed. The above code doesn't store this name anywhere but in a realistic implementation you will store it in some variable or auxiliary object.

Notice all the other methods such as Insert() and Update(). Although they lack full-fledge implementation, the important part is in place. As you can see, all of them return "this". That means they do insert, update, delete, or select operation and return the same context (the CurdOnTable object).

Now you can call the methods using chaining syntax as shown below:

var crud = new CrudOnTable("Employees")
    .Insert("Nancy Davolio")
    .Update(1, "Andrew Fuller")
    .Delete(3)
    .Select(1, out data);

Since all the methods return the same CrudOnTable, you can chain them as shown above. The resultant code is tidy and more readable than the earlier fragment.

The CrudOnTable object returned from the Select() method is assigned to the crud variable and it will have the final state after executing all the earlier methods in the chain. 

Example 2 - Processing an order

In the previous example all the methods of the chain were independent of one another. You could have even omitted calling all the methods. For example, you could have used only Insert() and Delete() methods. However, at times you need to device methods that are related to a task. Upon executing the complete chain the final result is obtained.

Suppose you are building an order processing system. You might create a set of methods to complete the task of processing the order. These methods are shown below:

var order = new Order()
    .AddCustomerDetails("Customer 1")
    .AddItem("ABCD", 10)
    .AddItem("PQRS", 20)
    .AddShippingDetails("address","city","postalcode")
    .Process();

As you can see, the code creates a new Order object. Then a set of chained methods is called on the object. The AddCustomerDetails() is supposed to add customer details for the order. One or more AddItem() calls add order items. The AddShippingDetails() method fills the shipping details for the order. Finally, the Process() method places the order in the system and does the required processing.

So, in this case you use these methods as one set. And they are required to successfully complete the task. The Order class used by the above code fragment is shown below:

public class Order
{
    public Order AddCustomerDetails(string name)
    {
        return this;
    }

    public Order AddItem(string code, int qty)
    {
        return this;
    }

    public Order AddShippingDetails(string address,
        string city,
        string postalcode)
    {
        return this;
    }

    public Order Process()
    {
        return this;
    }
}

In this case the Process() method acts as a end method or terminating method that finishes the task and returns the final Order object. 

Example 3 - Enforcing a sequence of operations

In the preceding example you created a set of methods to complete the order processing task. Although this might work as expected, it has its own problem. These methods are supposed to be called in a specific order. And currently there is no way to enforce that. For example, consider the following code fragment :

var order = new Order()
    .AddCustomerDetails("Customer 1")
    .AddShippingDetails("address","city","postalcode")
    .Process();

This code doesn't call AddItem() method at all. So, the Process() method is not going to work as expected. Similarly, you may want that AddCustomerDetails() must be called prior to calling any other method in the chain.

To enforce such a sequence you can resort to interfaces. To give you some idea let's see how interfaces can be used in such cases.

Consider the following interfaces:

public interface IAddOrderItem
{
    IAddOrShipItem AddItem(string code, int qty);
}

public interface IAddOrShipItem
{
    IAddOrShipItem AddItem(string code, int qty);
    IReadyToProcess AddShippingDetails(string address,
        string city,
        string postalcode);
}

public interface IReadyToProcess
{
    Order Process();
}

The IAddOrderItem interface contains AddItem() method. The AddItem() method returns IAddOrShipItem object. The IAddOrShipItem interface contains AddItem() and AddShippingDetails() methods. The AddShippingDetails() method returns IReadyToProcess object. The IReadyToProcess interface contains Process() method. And the Process() method returns Order object.

Once these interfaces are ready, you will implement all of them on the Order class:

public class Order:IAddOrderItem, IAddOrShipItem, 
IReadyToProcess
{
  ...
}

You will ensure that initially AddCustomerDetails() should be called. To enforce this rule you need to make the class constructor private as shown below:

private Order() { }

Since the Order class implements IAddOrderItem interface, the implementation of AddCustomerDetails() will be as follows:

public static IAddOrderItem AddCustomerDetails
(string name)
{
    return new Order();
}

As you can see, AddCustomerDetails() is a static method and creates a new Order object. This context will flow through the rest of the methods in the chain.

The implementation of AddItem() will now look like this:

public IAddOrShipItem AddItem(string code, int qty)
{
    return this;
}

Notice that since Order class implements IAddOrShipItem interface, AddItem() can return "this".

On the same lines, implementation of AddShippingDetails() will look like this:

public IReadyToProcess AddShippingDetails(string address,
    string city,
    string postalcode)
{
    return this;
}

Finally, the Process() method will look like this:

public Order Process()
{
    return this;
}

If you try to use the Order class, you will be required to call the AddCustomerDetails() first because that's what will be available to you:

Once you call AddCustomerDetails(), you can then invoke AddItem() method one or more times.

Upon calling AddItem() one or more times, you can call AddShippingDetails().

Finally, you can terminate the chain by calling the Process() method.

You might have guessed that enforcing such constraints requires thoughtful designing of the system because there could be many permutations and combinations of the method chains. 

That's it for now! Keep coding!!


Bipin Joshi is an independent software consultant, trainer, author, yoga mentor, and meditation teacher. He has been programming, meditating, and teaching for 24+ years. He conducts instructor-led online training courses in ASP.NET family of technologies for individuals and small groups. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Facebook  Twitter  LinkedIn  YouTube

Posted On : 20 July 2020


Tags : ASP.NET ASP.NET Core LINQ MVC .NET Framework C# Visual Studio


Subscribe to our newsletter

Get monthly email updates about new articles, tutorials, code samples, and how-tos getting added to our knowledge base.

  

Receive Weekly Updates