Building your First async fluent API using interface extension methods pattern
Tags: xamarin, dotnet, csharp, asyncawait
Published: 2020-04-11 23:00:18

---
title: Building your First async fluent API using interface extension methods pattern
published: true
date: 2020-04-11 20:22:45 UTC
tags: xamarin,dotnet,csharp,asyncawait
canonical_url: 
---

![](https://cdn-images-1.medium.com/max/1024/1*sXO3lbPj9YKYuSSRer2ZEg.png)

Fluent Interface is an advanced API design that really on extension methods and methods chaining. When of the most famous examples of fluent API is the linq extension methods for IEnumerable.

```
var passed=Students.Where(s=>s.Passed).Select(s=>s.Name).ToList();
```

In the asynchronous Programming, async/await, fluent APIs are kind of limited due to the nature of the Task object that it is hot build default, in this article, we will overcome this problem and will build a small library that allows fluent extension methods.

as an example,

```
var data=await GetDataAsync()
         .AsRepeatable(TimeSpan.FromSeconds(10))
         .FirstOrDefaultAsync(data=>data.Any());
```

another example could be

```
var data=await GetNewsAsync()
         .Where(newsList=>newsList.Date>=DateTime.Today)
         .SelectMany(newsList=>newsList.NewsItems)
         .ToList();
```

Just to give you an idea of how this code could be written using Imperative approach

```
 var newsList=await GetNewsAsync();
 if(newsList.Date>=DateTime.Today)
    {
       return newsList.Select(news=>news.NewsItems).ToList();
    }
else
       return new List<NewsItem>();
```

It is up to you to choose which code fashion you would like, if you like the second one, you can stop reading this article as in the rest of the article we will extend the c sharp language to make the first one applicable.

Good you decided to continue that show that you are a very elegant software engineer so please grape your coffee and you can invite me on as well using

[Buy AhmedFouad a Coffee. ko-fi.com/ahmedfouad](https://ko-fi.com/ahmedfouad)

### Step 1: Convert your async Task<T> to Task<Option<T>>

This will help us to get rid of the NullReferenceExceptions and concentrate only on the extension methods.

```
public static Func<Task<Option<T>>> ToOption<T>(this Func<Task<T>> context)
{
     return new Func<Task<Option<T>>>(async () =>{
     try
       {
          var result = await context.Invoke();
          return result.SomeNotNull();
       }
     catch (Exception e)
       {
          return Option.None<T>();
       }});

}
```

This method simply invokes the async method and return Option.None when the value is null or exception happened or the value as some when there is a value.

we will need to install the option type nugget package

[Optional 4.0.0](https://www.nuget.org/packages/Optional/)

### Step 2: Build a Wrapper class in which we will implement our extension methods

```
public class ExtendedTask<T>
    {
        private readonly Func<Task<Option<T>>> \_taskOption;
        public ExtendedTask(Func<Task<T>> task)
        {
            \_taskOption = task.ToOption();
        }
        public ExtendedTask(Func<Task<Option<T>>> task)
        {
            \_taskOption = task;
        }
    }
```

form here it is very easy to implement our extension methods, we will just delegate the implementation to the option type.

```
public ExtendedTask<T> Where(Func<T,bool> condition)
        {
            var conditionedTask = \_taskOption.Select(func => new Func<Task<Option<T>>>(async () =>
            {
                var result = await func.Invoke();
                return result.Where(condition);
            }));

            return new ExtendedTask<T>(conditionedTask);
        }
```

It will return the new ExtendedTask<T> of value when the condition is meet and ExtendedTask<T> of None otherwise.

Now we will implement the select method and select async method using the same strategy.

```
public ExtendedTask<TP> Select<TP>(Func<T,TP> selector)
        {
            var conditionedTask = \_taskOption.Select(func => new 
            Func<Task<Option<TP>>>(async () =>
            {
                var result = await func.Invoke();

                return result.Select(selector);
            }));

          return new ExtendedTask<TP>(conditionedTask);
        }

public ExtendedTask<TP> SelectAsync<TP>(Func<T, Task<TP>> selector)
        {
            var conditionedTask = \_taskOption.Select(func => new  
            Func<Task<Option<TP>>>(async () =>
            {
                var result = await func.Invoke();

                var [@select](http://twitter.com/select) = await result.Select(selector.Invoke)
                 .ValueOr(()=>Task.FromResult(default(TP)));

                return [@select](http://twitter.com/select).SomeWhen(p =>
                {
                    var b = p.Equals(default(TP));
                    return !b;
                });
            }));
```

### Step 3: Implement the AsTask() method

```
public async Task<T> AsTask()
        {
            return (await \_taskOption.Select(async task => await 
                    task())).ValueOrDefault();
        }
```

This method simply returns a new task that executes the decorated task and will simply return the default of T when the value is None.

### Step4: Implement AsRepeatable() method

As the repeatable method is a transformation method that transforms a scalar Task<T> to a Vector IAsyncEnumerable<T>

```
public IAsyncEnumerable<T> AsRepeatable()
        {
            return new TaskAsyncEnumerable<T>( \_taskOption);
        }
        public IAsyncEnumerable<T> AsRepeatable(TimeSpan timeSpan)
        {
            return new TaskAsyncEnumerable<T>(\_taskOption ,timeSpan);
        }
```

And here is the Implementation of TaskAsyncEnumerable<T>

{% gist https://gist.github.com/TheFo2sh/e91ca3c048c6a76a797321112277d6a1 %}

It is quite straight forward The enumerator will keep executing the task on iterating and will only stop when the Iterating stop or when the value becomes null.

### Step 5: Let’s try it

```
var getDataAsync = new ExtendedTask<News>(GetDataAsync);
var data = await getDataAsync
                .AsRepeatable(TimeSpan.FromSeconds(1))
                .FirstOrDefaultAsync(data => data.Items.Any());
```

### Step 6

If you like the article please share it, follow me on medium and on twitter to get my upcoming

[Ahmed Fouad](https://twitter.com/MCC_Ahmed)

and pay me the coffee at

[Buy AhmedFouad a Coffee. ko-fi.com/ahmedfouad](https://ko-fi.com/ahmedfouad)