Calling common async code from a derived method I'm implementing a number of classes in C# that have async methods. However, each of these methods needs to implement some boilerplate code that is common to all. Therefore I've implemented the common code in an async method of a base class; the async methods on the derived classes then call this base class method.

Here's the base class, containing the method that does the common stuff (GetResultAsync).

namespace Redacted
{
    abstract class RepositoryBase : IRepository
    {
        protected RepositoryBase(IRepositoryConfiguration configuration)
        {
            Configuration = configuration;
        }

        protected IRepositoryConfiguration Configuration { get; private set; }

        protected FleetContext CreateDatabaseContext()
        {
            return new FleetContext(Configuration.DatabaseConnectionString);
        }

        protected async Task&lt;IApiResult&lt;TValue&gt;&gt; GetResultAsync&lt;TValue&gt;(
            IApiCallerContext context,
            Func&lt;FleetContext, CancellationToken, Task&lt;TValue&gt;&gt; getTask)
        {
            using (new SynchronizationContextChange())
            using (FleetContext db = CreateDatabaseContext())
            {
                bool isSystemOnline = await db.IsSystemOnlineAsync();
                if (!isSystemOnline)
                {
                    return ImmutableApiResult&lt;TValue&gt;.Offline;
                }

                bool isValidSession = await db.IsValidSessionAsync(context.Caller);
                if (!isValidSession)
                {
                    return ImmutableApiResult&lt;TValue&gt;.Blocked;
                }

                Task&lt;TValue&gt; task = getTask(db, context.CancellationToken);
                TValue value = await task;

                return ImmutableApiResult.Create&lt;TValue&gt;(value);
            }
        }
    }
}


Basically, I have an Entity Framework database context (FleetContext) that exists for the duration of the call. I then perform some common DB-related tasks by calling custom async methods that have been added to the context class. Depending on the result of these calls, I may exit the method early: in such cases, the IApiResult object returned by the method is different than when the method runs through to the end normally.

Here's an example of a derived class that contains a method which calls the base class:

namespace Redacted
{
    sealed class CompanyRepository : RepositoryBase, ICompanyRepository
    {
        public CompanyRepository(IRepositoryConfiguration configuration)
            : base(configuration)
        {
        }

        public Task&lt;IApiResult&lt;ICompanyIdentity&gt;&gt; GetCompanyIdentityAsync(int companyId, IApiCallerContext context)
        {
            return GetResultAsync&lt;ICompanyIdentity&gt;(
                context,
                async (db, cancellationToken) =&gt;
                {
                    Company company = await db.Companies.FindAsync(cancellationToken, companyId);
                    return ImmutableCompanyIdentity.Create(company);
                }
                );
        }
    }
}


As you can see I'm using an asynchronous anonymous function to return the Task object required by the GetResultAsync method.

This all works but seems somewhat inside-out to me, in that the API method (GetCompanyIdentityAsync) passes a function to the base class, rather than the more typical approach of the derived class calling the base method as part of its normal processing.

Am I worrying unnecessarily, or are there obvious alternate ways of calling the boilerplate code from the derived classes?
In your code you create 2 boolean variables for a simple if statement conditional, personally I think that you shouldn't create these variables unless you are going to use them in more than one place or for complex condition statements.


        using (FleetContext db = CreateDatabaseContext())
        {
            bool isSystemOnline = await db.IsSystemOnlineAsync();
            if (!isSystemOnline)
            {
                return ImmutableApiResult&lt;TValue&gt;.Offline;
            }

            bool isValidSession = await db.IsValidSessionAsync(context.Caller);
            if (!isValidSession)
            {
                return ImmutableApiResult&lt;TValue&gt;.Blocked;
            }

            Task&lt;TValue&gt; task = getTask(db, context.CancellationToken);
            TValue value = await task;

            return ImmutableApiResult.Create&lt;TValue&gt;(value);
        }



You can also avoid creating the Task variable at the end as well and just create the value.

using (FleetContext db = CreateDatabaseContext())
{
    if (!(await db.IsSystemOnlineAsync()))
    {
        return ImmutableApiResult&lt;TValue&gt;.Offline;
    }
    else if (!(await db.IsValidSessionAsync(context.Caller)))
    {
        return ImmutableApiResult&lt;TValue&gt;.Blocked;
    }

    TValue value = await (getTask(db, context.CancellationToken));

    return ImmutableApiResult.Create&lt;TValue&gt;(value);
}


This shortens the code a little bit and gets straight to the point.  Nothing really wrong with the way that you did it, and I haven't really done anything different here either, I just...well... golfed it a bit I guess.  I just didn't think we needed to create all those variables