Skip to content

A very simple implementation of IExecutor and IExecutorAsync.

License

Notifications You must be signed in to change notification settings

petar-m/executables.executors

Repository files navigation

Executables.Executors.Simple

NuGet

A very simple implementation of IExecutor and IExecutorAsync (M.Executables).

This is not a "real world" implementation, rather a starting point for something useful.

Executables.Executors.NetCoreExecutor

NuGet
read me

Executables.Executors.SimpleInjector

NuGet

An implementation of IExecutor and IExecutorAsync (M.Executables) utilizing SimpleInjector as IoC container.

Additional interfaces:

IScopeEndHandler - an action can be plugged in when scope ends, e.g. UnitOfWork.Commit/Rollback

IErrorHandler - an action the executor will call on exception, e.g. logging.

NOTE: SimpleInjectorExecutor propagates the exception after calling IErrorHandler.Handle leaving the environment to decide what to do.

IExecutorScope - obsolete

IScopedContext - an alternative scope provider when the environment does not provide a way to start/end scope, e.g. service executing recurring tasks in background.

Example:

error handler:

public class ExecutorErrorHandler : IErrorHandler
{
    // called from the executor
    public void Handle(Exception exception, Scope scope)
    {
        // log...

        // indicate there was error
        scope.SetItem("HasError", true);

        // force IScopeEndHandler to be called
        scope.Dispose();
    }
}  

scope end handler:

public class ScopeEndHandler : IScopeEndHandler
{
    public void Handle(Scope scope)
    {
        object hasErrorItem = scope.GetItem("HasError");
        var hasError = hasErrorItem == null ? false : (bool)hasErrorItem;
        if (hasError)
        {
            // clean up
        }
        else
        {
            // go on with the happy path
        }
    }
}  

setup:

container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

container.Register<IExecutor, SimpleInjectorExecutor>(Lifestyle.Scoped);
container.Register<IExecutorAsync, SimpleInjectorExecutor>(Lifestyle.Scoped);	

container.Register<IErrorHandler, ExecutorErrorHandler>(Lifestyle.Singleton);
container.Register<IScopeEndHandler, ScopeEndHandler>(Lifestyle.Scoped);

container.Register<IScopedContext, ScopedContext>(Lifestyle.Singleton);  

usage:

// with OWIN pipeline
appBuilder.Use(async (context, next) =>
{
    using (var scope = AsyncScopedLifestyle.BeginScope(container))
    {
        scope.WhenScopeEnds(() => scope.Container.GetInstance<IScopeEndHandler>().Handle(scope));
        await next();
    }
});

// controller example	
public class SomeController : ApiController
{
    private readonly IExecutorAsync executor;

    public SomeController(IExecutorAsync executor)
    {
        this.executor = executor;
    }

    [HttpGet]
    public async Task<IHttpActionResult> Something()
    {
        var result = await executor.ExecuteAsync<SomeExecutable, Result>();
        return Ok(result);
    }
}

...

// outside of OWIN pipeline
// ScopedContext will create new scope with IScopeEndHandler set, 
// execute the action passing arguments resolved from the scope and dispose the scope
var scope = container.GetInstance<IScopedContext>());
scope.Execute<IExecutor>(executor => executor.Execute<SomeExecutable>());

About

A very simple implementation of IExecutor and IExecutorAsync.

Resources

License

Stars

Watchers

Forks

Packages

No packages published