Giter Site home page Giter Site logo

Comments (11)

jbogard avatar jbogard commented on July 20, 2024

If you need an order, you need to build that in. What are you doing that requires a specific order?

from mediatr.

ThisNoName avatar ThisNoName commented on July 20, 2024

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.

jbogard avatar jbogard commented on July 20, 2024

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.

jbogard avatar jbogard commented on July 20, 2024

Forgot to mention - the order in which I apply the decorators is the order in which things are run, russian doll style.

from mediatr.

ThisNoName avatar ThisNoName commented on July 20, 2024

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.

jbogard avatar jbogard commented on July 20, 2024

Ah, you need access to BOTH the request and response?

from mediatr.

ThisNoName avatar ThisNoName commented on July 20, 2024

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.

jbogard avatar jbogard commented on July 20, 2024

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.

ThisNoName avatar ThisNoName commented on July 20, 2024

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.

ThisNoName avatar ThisNoName commented on July 20, 2024

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.

jbogard avatar jbogard commented on July 20, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.