Comments (11)
If you need an order, you need to build that in. What are you doing that requires a specific order?
from mediatr.
I'm trying to wrap the center business handler with things like validation, transaction, caching and auditing.
I tried the ValidationHanlder approach, but with open generic type, I can't easily update the TResponse from decorators. For example, caching needs to mark response as cached, business handler may mark result as staled while auditing needs to record UserA access ServiceB and get 100 Staled result, etc.
In Pre/Post handler, it's much easier to cast to a base response and make changes. But I couldn't figure out how to control the order. And besides the registered sequence, with auto wiring, it comes out like
Ping LogtPre AuditPre Pong LogPost AuditPost
while I would like to see
Ping AuditPre LogtPre Pong LogPost AuditPost
Any hints? Thanks.
from mediatr.
Do you need pre/post handlers? Can't you just wrap the inner handler with decorators? I can do that pretty easily with StructureMap:
var handlerType = cfg.For(typeof (IRequestHandler<,>));
handlerType.DecorateAllWith(typeof (LoggingHandler<,>));
handlerType.DecorateAllWith(typeof (AuthorizationHandler<,>));
handlerType.DecorateAllWith(typeof (ValidatorHandler<,>));
handlerType.DecorateAllWith(typeof (PipelineHandler<,>));
from mediatr.
Forgot to mention - the order in which I apply the decorators is the order in which things are run, russian doll style.
from mediatr.
I tried that one, but was having trouble dealing with concrete Request/Response. For example, if both Ping and Pong are inherit from base Request/Response, I can't pass them on to ValidationHanlder because it needsTRequest/TResponse.
public class PingHandler : IRequestHandler<Ping, Pong>
I tried to modify it to something like this
public class ValidatorHandler<TRequest, TResponse> : IRequestHandler<TRequest, Response>
where TRequest : IRequest<Response>
But it doesn't work for Request or if I try to pass in a PingResponse. Of course, I maybe able to create a concrete RequestHandler dealing with concrete Request/Response, but that seems to change everything. Guess I just didn't understand these generics very well. Or the framework is supposed to be flexible and not tie down to concrete.
Accessing Request/Response from the Pre/Post handler seems a lot easier, that's where start trying to wire multiple in certain sequence. Not sure if I truly understand how everything supposed to be.
from mediatr.
Ah, you need access to BOTH the request and response?
from mediatr.
In my current application, the base Request contains things like authenticated user, workstation Id, etc, the base Response has ResponseStatus, IsCached, etc. Reading incoming request is apparently needed everywhere, modifying response from Handler/Post is useful if I want to handle caching from the decorator. Although modifying Request pre handle can also be useful if I need something like TrimAllIncomingStringDecorator, I never actually did that one though.
The framework I'm using now has a handler like this
public interface IRequestHandler<TRequest> : IRequestHandler where TRequest : Request {
Response Handle(TRequest request); }
and "interceptor"
public interface IRequestHandlerInterceptor : IDisposable {
void BeforeHandlingRequest(RequestProcessingContext context);
void AfterHandlingRequest(RequestProcessingContext context); }
public class RequestProcessingContext {
public Request Request { get; private set; }
public Response Response { get; private set; } }
So I got used to the idea of having access to both Request and Response anywhere, casting them to base and making changes along the way.
Not sure if that's the best way. I like the flexibility of the open generic in many scenarios, but do miss the ability fine tuning details when authorization, validation, caching, transaction, auditing and logging are involved.
from mediatr.
Making changes to the request AND the response at the same time? You could still do this with a decorator:
public class AuditingHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse> {
private readonly IAuditService _auditor;
private readonly IRequestHandler<TRequest, TResponse> _inner;
public AuditingHandler(IAuditService auditor,
IRequestHandler<TRequest, TResponse> inner) {
_auditor = auditor;
_inner = inner;
}
public TResponse Handle(TRequest message) {
_auditor.AuditRequest(message);
var response = _inner.Handle(message);
_auditor.AuditResponse(response);
return response;
}
}
from mediatr.
That's reading request/response. Say I have a caching decorator and want to mark property IsCached=true in the base. My previous attempt, with influence from previous framework, ends up something like this:
var response = _inner.Handle(message);
var response2 = response as BaseResponse;
response2.IsCached = true;
return (TResponse)(object)response2;
It looks so wrong I didn't continue down that path. Now that I think about it, maybe I could use reflection to set the value instead of casting? Will give it a try. Thanks for the help.
from mediatr.
I think this worked:
public abstract class Request<TResponse> : IRequest<TResponse> {
public string UserId { get; set; } }
public class Response {
public bool IsCached { get; set; } }
public class PingRequest : Request<PingResponse> {
public string Message { get; set; } }
public class PingResponse : Response {
public string Message { get; set; } }
public class PingHandler : IRequestHandler<PingRequest, PingResponse> {
public PingResponse Handle(PingRequest request) { ... } }
Also, in the handler, there seems no need to cast. Either I missed something last time, or the Request/Response are structured better now
public class AuditingHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse> {
public TResponse Handle(TRequest request) {
if (request is Request<TResponse>) {
var req = request as Request<TResponse>;
req.UserId = " Id Changed";
var response = _inner.Handle(request);
if (response is Response)
var res = response as Response;
res.IsCached = true; }
return response; }
This way, I can decorate and track when needed, and use generics for misc calls to save a few keystrokes. Let me know if spot any potential issues. Thanks
P.S, now I'm not quite sure what use for Pre/Post/MediatorPipeline. Aren't they the same as the outermost handler?
from mediatr.
The advantage to the Pre/Post pipeline is that you can then use generic variance instead of testing for types. If your interface just implements a base type, you don't have to create a decorator, which is always created regardless of type.
from mediatr.
Related Issues (20)
- IPipelineBehavior<TRequest, TResponse> does not work in Android, but works in Windows HOT 5
- Would you consider a PR for a Roslyn component? HOT 1
- IPipelineBehavior not being executed when I have custom interface HOT 2
- [Question] DbContextPooling issue with INotifications when publish is executed HOT 4
- Can't get IPipelineBehavior to work in F# HOT 3
- I have problem with IRequestPreProcessor pipeline
- Logging any Exception thrown in a handler HOT 2
- Specify Lifetime in Handlers feature missing HOT 2
- docs: I'm able to edit the wiki HOT 3
- .NET 8 Calling IPublisher.Publish method throws ObjectDisposedException for IServiceProvider HOT 1
- "No service for type 'MediatR.IRequestHandler' has been registered." issue HOT 8
- Can't register MediatR in WorkerService project HOT 1
- Help registering pipeline behavior HOT 2
- Allow for an optional "Order" parameter to be set on implementations of pre, post, and exception handlers. HOT 5
- Issue : Pipelines does not get invoked when command has a mapping profile sub class HOT 1
- MediatR one notification handler HOT 8
- Issues with MediatR on .Net 8 and AWS Lambda HOT 2
- Order of execution of RequestPreProcessorBehavior changed with explicit processor registration? HOT 2
- IoC container issue with .NET 8 & minimal api HOT 3
- Add assembly with handlers without ServiceCollection HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from mediatr.