IGet 1.1.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package IGet --version 1.1.1                
NuGet\Install-Package IGet -Version 1.1.1                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="IGet" Version="1.1.1" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add IGet --version 1.1.1                
#r "nuget: IGet, 1.1.1"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install IGet as a Cake Addin
#addin nuget:?package=IGet&version=1.1.1

// Install IGet as a Cake Tool
#tool nuget:?package=IGet&version=1.1.1                

IGet

Instantiate classes that are NOT in your service collection via i.Get<Class>(). Idea: use i.Get<Handler>().Handle(request) instead of mediatR.Send(request) - for less code (in total) and more freedom.

serviceCollection.AddIGet();

Why?

Having MediatR working is nice. You might, however, like IGet better:

  • you don't need to implement any interface for your handlers.
  • creating a request class is optional.
  • have compile-time checks that all handlers exist.
  • use editor shortcuts to jump to a handler method immediately.
  • have a shorter StackTrace in case of an error.
  • have more control for designing complex processes.
  • etc.

IGet has only one responsibility - instantiating classes with their dependencies injected - but with this you can create MediatR-like structures easily. A basic IRequest-IRequestHandler structure needs less code if you use IGet and complex structures such as INotification-INotificationHandler are completely under your control.

Declaring a handler

Example 1

There is no need to implement IRequest and IRequestHandler<Request> or IRequest<Result> and IRequestHandler<Request, Result>. Choose another method name and use value type parameters if you want.

public class MyHandler
{
    private IConnectionFactory _connectionFactory;

    public MyHandler(IConnectionFactory connectionFactory)
    {
        _connectionFactory = connectionFactory;
    }

    public async Task<MyResult> ChooseASignature(int id)
    {
        // do something
    }
}
Example 2

Do you prefer synchronous code if possible? That's allowed!

public class MyHandler
{
    private ILogger<MyHandler> _logger;

    public MyHandler(ILogger<MyHandler> logger)
    {
        _logger = logger;
    }

    public void Handle()
    {
        // do something
    }
}

Sending a request

In the examples below i is the IGet instance where you call Get on. (Like mediator might have been the name of the variable for a IMediator instance where you called Send on.)

Example 1
var result = i.Get<MyHandler>().AnyRandomSignature(1);
Example 2
var handler = i.Get<MyHandler>();
handler.Handle();
Example 3
var result = await i.Get<MyHandler>().HandleAsync(new MyRequest
{
    Id = 2
});
Example 4
var result = i.Get<MyHandler>().Handle(request);

Because you get the handler via generics, your code is type-checked by the compiler - therefore you know that each request has a handler immediately. Also, you can place your cursor on the class's method and press F12 to quickly navigate to the method declaration.

More complex scenarios

Example 1

Handlers may get other handlers to do stuff for them, like validation, pre-processing and post-processing.

var result = await i.Get<MoreComplexHandler>().Handle(request);
public class MoreComplexHandler
{
    private ILogger<MoreComplexHandler> _logger;
    private IGet i;

    public MoreComplexHandler(IGet iget, ILogger<MoreComplexHandler> logger)
    {
        _logger = logger;
        i = iget;
    }

    public Result<WhatWasAskedFor> Handle(Request request)
    {
        try
        {
            var validationResult = i.Get<Validator>().Validate(request);
            if (!validationResult.IsValid)
            {
                return Result.Fail<WhatWasAskedFor>(validationResult.Message);
            }

            i.Get<PreProcessor>().Prepare(request);
            var whatWasAskedFor = i.Get<MainProcessor>().Handle(request);

            try
            {
                i.Get<PostProcessor>().DoLessImportantStuffWith(request, whatWasAskedFor);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "PostProcessor failed for request {requestId}.", request.Id);
            }

            return Result.Success(whatWasAskedFor);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Unexpected error for request {requestId}.", request.Id);
            return Result.Fail<WhatWasAskedFor>("Something went wrong. Try again later.");
        }
    }
}
Example 2

The functionality of MediatR's INotification-INotificationHandler combination can be created via something like this:

await i.Get<NotificationPublisher>().PublishAsync(notification);
public class NotificationPublisher
{
    private IGet i;

    public NotificationPublisher(IGet iget)
    {
        i = iget;
    }

    public async Task PublishAsync(Notification notification)
    {
        try
        {
            await i.Get<FirstHandler>().HandleAsync(notification);
        }
        catch { }
        try
        {
            await i.Get<SecondHandler>().HandleAsync(notification);
        }
        catch { }
        try
        {
            i.Get<ThirdHandler>().Handle(notification);
        }
        catch { }
    }
}

Notes:

  • Exceptions should be logged in the catch blocks.
  • Let's say that you have several handlers that implement INotificationHandler<ChallengeAccepted> and via reflection you get all those handlers as a Type[] (in a static property of type Lazy<Type[]>). Then use i.Get<T>(type) for instantiating the type and casting it to T:
foreach (Type handlerType in LazyChallengeAcceptedNotificationHandlers)
{
    try
    {
        var handler = await i.Get<INotificationHandler<ChallengeAccepted>>(handlerType);
        await handler.Handle(challengeAcceptedNotification);
    }
    catch { }
}
Example 3

You may want multiple handlers to have certian behaviour, for example logging their execution time. You could create a base class for (a subset of) your handlers:

public abstract class BaseHandler<THandler,TRequest, TResponse>
    where THandler : notnull
    where TRequest : notnull
{
    protected readonly ILogger<THandler> _logger;
    protected readonly IDbConnectionFactory _connectionFactory;
    protected readonly IHostEnvironment _hostEnvironment;

    public BaseHandler(IBaseHandlerServices baseHandlerServices)
    {
        _logger = baseHandlerServices.LoggerFactory.CreateLogger<THandler>();
        _connectionFactory = baseHandlerServices.ConnectionFactory;
        _hostEnvironment = baseHandlerServices.HostEnvironment;
    }
    public async Task<TResponse> HandleAsync(TRequest request, CancellationToken cancellationToken = default)
    {
        HandleBefore(request);
        var result = await HandleCoreAsync(request, cancellationToken);
        HandleAfter();
        return result;
    }

    private void HandleBefore(TRequest request)
    {
        if (!_hostEnvironment.IsProduction())
        {
            _logger.LogInformation("Start handling request {RequestMembers}.", request.ToKeyValuePairsString());
        }
        StartTime = DateTime.UtcNow;
    }
    DateTime StartTime;
    protected abstract Task<TResponse> HandleCoreAsync(
        TRequest request, 
        CancellationToken cancellationToken);
    private void HandleAfter()
    {
        var totalMilliseconds = (DateTime.UtcNow - StartTime).TotalMilliseconds;
        if (!_hostEnvironment.IsProduction() || totalMilliseconds > 500)
        {
            _logger.LogInformation("Finished in {TotalMilliseconds}ms.", totalMilliseconds);
        }
    }
}

Inherit:

public class ProductOverviewQueryHandler 
    : BaseHandler<ProductOverviewQueryHandler, Query, Result>
{
    public ProductOverviewQueryHandler(IBaseHandlerServices baseHandlerServices) 
        : base(baseHandlerServices)
    { }

    protected override async Task<Result> HandleCoreAsync(
        Query query,
        CancellationToken cancellationToken)
    {
        await using var connection = await _connectionFactory.GetOpenConnectionAsync(cancellationToken);

        // execute

        return new Result
        {
            // set properties
        };
    }
}

Use:

var result = await i.Get<ProductOverviewQueryHandler>().HandleAsync(query);

Try it out

The examples above give an idea of how you can be creative with IGet. Share your own examples online to spread the word about IGet.

If you're interested in the source code of this library, then use IGet in Visual Studio and press F12 with your cursor on the AddIGet() extension method.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on IGet:

Package Downloads
IGet.GetAll

Extends IGet. Get an IEnumerable of class instances (with their dependencies injected) via i.GetAll<IMyInterface>() or i.GetAll<MyBaseClass>(). Additional setup: serviceCollection.AddIGetAll(new [] { typeof(Startup).Assembly, ... }). See the readme for many examples.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.1.8 17,394 12/13/2023
1.1.7 133 12/13/2023
1.1.6 5,161 4/12/2023
1.1.5 970 3/29/2023
1.1.4 297 3/21/2023
1.1.3 297 3/20/2023
1.1.2 190 3/19/2023
1.1.1 326 3/16/2023
1.1.0 200 3/15/2023
1.0.14 198 3/15/2023
1.0.13 209 3/14/2023
1.0.12 207 3/14/2023
1.0.11 212 3/14/2023
1.0.10 208 3/14/2023
1.0.9 212 3/13/2023
1.0.8 215 3/13/2023
1.0.7 205 3/13/2023
1.0.6 194 3/13/2023
1.0.5 205 3/12/2023
1.0.4 222 3/12/2023
1.0.3 195 3/11/2023
1.0.2 211 3/10/2023
1.0.1 227 3/10/2023
1.0.0 227 3/10/2023
1.0.0-alpha 147 3/10/2023

v1.0.*: updates of the readme.
 v1.1.0: add T Get<T>(Type type).
 v1.1.*: updates of the readme.