MediatR and ...

서론

MediatR 을 이용하는 여러가지 방법에 대해 알아보자. 


Request/Response

IRequest 를 통해 Command 를 생성하고
IRequestHandler <CommandType, OutputType> 을 통해 handler 처리

1
public class Ping : IRequest<string> { }

1
2
3
4
5
6
7
public class PingHandler : IRequestHandler<Ping, string>
{
    public Task<string> Handle(Ping request, CancellationToken cancellationToken)
    {
        return Task.FromResult("Pong");
    }
}

1
2
var response = await mediator.Send(new Ping());
Debug.WriteLine(response); // "Pong"

해당 event 전송 방식은 response 가 올때 까지 대기 하는 방식 이다.

Response 가 없을 경우에 처리. 

1
2
3
4
5
6
7
8
public class OneWay : IRequest { }
public class OneWayHandlerWithBaseClass : AsyncRequestHandler<OneWay>
{
    protected override Task Handle(OneWay request, CancellationToken cancellationToken)
    {
        // Twiddle thumbs
    }
}



Notification

INotification 을 통해 Command 를 생성하고
INotificationHandler<CommandType> 을 통해 handler 처리

Request/Response 방식과의 차이점은 response 의 유무와 1:1 이냐 1:n 이냐의 차이이다.
Request 는 Response 를 대기 하지만
Notification 은 publish 후 잊어버린다.

1
public class Ping : INotification { }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class Pong1 : INotificationHandler<Ping>
{
    public Task Handle(Ping notification, CancellationToken cancellationToken)
    {
        Debug.WriteLine("Pong 1");
        return Task.CompletedTask;
    }
}

public class Pong2 : INotificationHandler<Ping>
{
    public Task Handle(Ping notification, CancellationToken cancellationToken)
    {
        Debug.WriteLine("Pong 2");
        return Task.CompletedTask;
    }
}

1
await mediator.Publish(new Ping());


PipeLineBehavior

MediatR 의 execute 전과 후에 작업을 추가 할 수 있다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class AppLoggingBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
    private readonly ILogger<AppLoggingBehaviour<TRequest, TResponse>> _logger;
    public AppLoggingBehaviour(ILogger<AppLoggingBehaviour<TRequest, TResponse>> logger)
    {
        _logger = logger;
    }
    public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
    {
        string requestName = typeof(TRequest).Name;
        string unqiueId = Guid.NewGuid().ToString();
        _logger.LogInformation($"Begin Request Id:{unqiueId}," +
            $" request name:{requestName},\nRequest = " +
            $"{JsonSerializer.Serialize(request,new JsonSerializerOptions{WriteIndented = true})}");
        var timer = new Stopwatch();
        timer.Start();
        var response = await next();
        timer.Stop();
        _logger.LogInformation($"Begin Request Id:{unqiueId}, " +
            $"request name:{requestName},\nResponse = " +
            $"{JsonSerializer.Serialize(response,new JsonSerializerOptions { WriteIndented = true })}" +
            $"\ntotal request time:{timer.ElapsedMilliseconds}");
        return response;
    }
}


Program.cs 에 서비스 등록





Request , Response 추가
public class GetUserRequest:IRequest<UserResponse>
{
    public string UserId { get; set; } = string.Empty
}
public class UserResponse
{
    public string Id { get; set; } = string.Empty;
    public string Name { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
}


Handler 추가

public class GetUserRequestHandler : IRequestHandler<GetUserRequest, UserResponse>
{
    private List<UserResponse> _userResponses = new List<UserResponse>()
    {
        new UserResponse
        {
             Id = "1",
             Name="First",
             Email = "First@email.com"
        },
        new UserResponse
        {
             Id = "2",
             Name="Second",
             Email = "Second@email.com"
        },
        new UserResponse
        {
             Id = "3",
             Name="Third",
             Email = "Third@email.com"
        },

    };
    public async Task<UserResponse> Handle(GetUserRequest request, CancellationToken cancellationToken)
    {
        var user = _userResponses.Where(u => u.Id.Equals(request.UserId, 
                    StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
        if (user == null) throw new Exception("Not found user");
        return await Task.FromResult(user!);
    }
}


Controller 에 method 추가
[HttpGet("ping")]
public async Task<string> SendPing()
{
    await _mediator.Send(new Ping());
    return "pong";
}

[HttpGet("user")]
public async Task<UserResponse> GetUser(string id)
{

    return await _mediator.Send(new GetUserRequest
    {
        UserId = id
    });
}


Test


관련영상

댓글

이 블로그의 인기 게시물

Mediator

ASPNET 6 Web Api Basic Tutorial 1 / 2 (Swagger, SeriLog, MediatR, EntityFrameworkCore, Scrutor)

Dependency Injection Customization