IGet 1.1.3
See the version list below for details.
dotnet add package IGet --version 1.1.3
NuGet\Install-Package IGet -Version 1.1.3
<PackageReference Include="IGet" Version="1.1.3" />
paket add IGet --version 1.1.3
#r "nuget: IGet, 1.1.3"
// Install IGet as a Cake Addin #addin nuget:?package=IGet&version=1.1.3 // Install IGet as a Cake Tool #tool nuget:?package=IGet&version=1.1.3
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)
.
serviceCollection.AddIGet();
Why?
MediatR has positively shaped code bases of developers for many years. 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's method immediately.
- have a shorter StackTrace in case of an error.
- have more control to design complex processes.
- IGet is easier to understand than MediatR and it therefore might save money.
- IGet is extremely lightweight - less code often means fewer bugs.
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. - If you find the example above too risky - because you might forget to register a newly created handler in the publisher, then have a look at IGet.GetAll. You can ask IGet.GetAll to return an instance of each class that implements a certain interface, for example
IMyNotification<MyRequest>
. It usesi.Get<T>(type)
from this library for instantiating thetype
and casting it toT
and it has a "memory" to increase performance on next calls.
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.
Product | Versions 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. |
-
.NETStandard 2.0
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,776 | 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 | 207 | 3/12/2023 |
1.0.4 | 222 | 3/12/2023 |
1.0.3 | 197 | 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.