Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/megafetis/conveyr

The library takes code reuse to a new level. Define one handler for interface and use it for many classes
https://github.com/megafetis/conveyr

conveyor conveyor-handling dependencyinjection handlers processing

Last synced: about 1 month ago
JSON representation

The library takes code reuse to a new level. Define one handler for interface and use it for many classes

Awesome Lists containing this project

README

        

# ConveyR - Handling of business objects by shared interfaces
=======
[![NuGet](https://img.shields.io/nuget/dt/ConveyR.svg)](https://www.nuget.org/packages/ConveyR/)
[![NuGet](https://img.shields.io/nuget/vpre/ConveyR.svg)](https://www.nuget.org/packages/ConveyR/)

Simple implementation of conveyor handling in .NET.
The library takes code reuse to a new level.
In-process object handling with no dependencies.

## Conveyor handling of business objects:

Write your `AbstractProcessHandler` business-logic handlers for every business interfaces. Optionally you can pass interfaces for payload too.
Run conveyor to handle each business object of several classes, if they have a common interfaces.

### Installing ConveyR

You should install [ConveyR with NuGet](https://www.nuget.org/packages/ConveyR):

Install-Package ConveyR

Or via the .NET Core command line interface:

dotnet add package ConveyR

Use this library to define handlers once and use them to handle different objects with shared interfaces or shared base classes.
Lib contains:
* `IConveyor` interface to use as entry point to handle
* `IProcessHandler` and `AbstractProcessHandler` to define handlers
* delegate `ServiceFactory` for connecting with any DI containers. [Extensions for Microsoft.DependencyInjection](https://www.nuget.org/packages/ConveyR.Extensions.Microsoft.DependencyInjection/)

### Common usage (Example):

### Define your domain classes and interfaces:

```cs
public class EntityClass1: IEntity, IHasNaming, IHasDescription
{
public string Id {get; set;}
public string Name {get; set;}
public string Description {get; set;}
}

public class EntityClass2: IEntity, IHasNaming
{
public string Id {get; set;}
public string Name {get; set;}
}

```

```cs

interface IEntity
{
string Id {get; set;}
}

interface IHasNaming
{
string Name {get; set;}
}

interface IHasDescription
{
string Description {get; set;}
}
```

### Define DTO domain model classes:

```cs

interface IHasNamingPayload
{
string Name {get; set;}
}

interface IHasDescriptionPayload
{
string Description {get; set;}
}

class EditEntityModel1: IHasNamingPayload,IHasDescriptionPayload
{
public string Name {get; set;}
public string Description {get; set;}
}

```

### Define Handlers from ``AbstractProcessHandler<,>`` or ``IProcessHandler<,>``:

```cs

// IEntity handler without payload
class GenerateIdHandler:AbstractProcessHandler
{
protected override Task Process(TestEntitiesStore context, IEntity entity, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(entity.Id))
{
entity.Id = Guid.NewGuid().ToString("N");
// You have access to context object
context._someUnitOfWork.SomeMethod(entity);
}

return Task.CompletedTask;
}
}

// IHasNaming handler with payload
class ChangeNameHandler:AbstractProcessHandler
{
protected override Task Process(TestEntitiesStore context, IHasNaming entity, IHasNamingPayload payload,CancellationToken cancellationToken = default)
{
if(payload.Name==null)
throw new ArgumentNullException("Name","Entity name must be named");
entity.Name = payload.Name;
return Task.CompletedTask;
}
}

// IHasDescription handler with payload
class ChangeDescriptionHandler: AbstractProcessHandler
{
protected override Task Process(TestEntitiesStore context, IHasDescription entity, IHasDescriptionPayload payload, CancellationToken cancellationToken = default)
{
entity.Description = payload.Description;
return Task.CompletedTask;
}
}

```
### Start processing in your store or controller:

``MyStore `` is some class, where may be started handling.

```cs
class MyStore
{
private readonly IConveyor _conveyor;
public readonly ISomeUnitOfWork _someUnitOfWork;
public MyStore(IConveyor conveyor)
{
_conveyor = conveyor;
_someUnitOfWork = new SomeUnitOfWork();
}

public async Task AddOrSaveEntity(IEntity entity,object payload = null)
{
await _conveyor.Process(this,entity,payload); // the conveyor will find all required handlers and apply them
}
}

//...

var store = new MyStore(_conveyor);
var entity = new EntityClass1();
var entity2 = new EntityClass1();
var payload = new EditEntityModel1()
{
Name = "Name 1",
Description = "Description 1",
}

store.AddOrSaveEntity(entity,payload);
store.AddOrSaveEntity(entity2,payload);

```

To register handlers you can use DI container:

```cs

var services = new ServiceCollection();
services.AddConveyR();
var provider = services.BuildServiceProvider();

```
...

```cs

var conveyor = _serviceProvider.GetService();
// ...

```
or implement some simple ``ServiceFactory``

```cs
public class SimpleServiceFactory
{
public SimpleServiceFactory(params Type[] handlerTypes)
{
ServiceFactoryExtensions.SetHandlerTypes(handlerTypes);
}
public IEnumerable GetServices(Type contextType, Type entityType, Type payloadType = null, string processCase=null)
{
var types = ServiceFactoryExtensions.GetProcessServiceTypes(contextType, entityType, payloadType, processCase);

if(!types.Any())
yield break;

foreach (var type in types)
{
var h = Activator.CreateInstance(type);
yield return h;
}
}
}

var factory = new SimpleServiceFactory(typeof(ChangeNameHandler), typeof(ChangeDescriptionHandler),typeof(GenerateIdHandler));

var conveyor = new Conveyor(factory.GetServices);

var myStore = new MyStore(conveyor);

```
With DI Microsoft.DependencyInjection:

#### You can lable handlers to split them into groups and manage ordering of handling:

```cs

[ProcessConfig(Order=1,Group="aftercommit")]
class WriteToLogHandler:AbstractProcessHandler
{
protected override Task Process(TestEntitiesStore context, IEntity entity, CancellationToken cancellationToken = default)
{
Console.Writeline($"{entity.Id} stored");
return Task.CompletedTask;
}
}

//...

class MyStore
{
private readonly IConveyor _conveyor;
public readonly ISomeUnitOfWork _someUnitOfWork;
public MyStore(IConveyor conveyor)
{
_conveyor = conveyor;
_someUnitOfWork = new SomeUnitOfWork();
}

public async Task AddOrSaveEntity(IEntity entity,object payload = null)
{
await _conveyor.Process(this,entity,payload); // the conveyor will find all required handlers and apply them
}

public async Task AfterSaveEntity(IEntity entity,object payload = null)
{
await _conveyor.Process(this,entity,payload,"aftercommit");
}

}

```

Please give a star if the library is useful for you :smiley: