MediatR发送对象而不键入

时间:2016-06-27 22:17:01

标签: c# owin mediatr

如果我发送HTTP Get请求:

/api/Company/1

我有OwinMiddleware我正在使用context来确定path的{​​{1}}和json内容。

要知道使用哪个异步请求,我有一个IAsyncRequest<T> Type路径的映射

IAsyncRequest<T>

我使用var mappings = new Dictionary<string, Type> { ["api/Company/{id}"] = typeof(GetCompanyRequest) } Type request; var result = mappings.TryGetValue(context.Requst.Path.Value, out request); 创建JObject

的实例
GetCompanyRequest

我使用var get = new JObject { ["id"] = "1" /* obtained from the url */ } var instantiatedRequest = JObject.ToObject(request); 的原因是对于PUT和POST请求,我将JSON主体直接反序列化为请求。

拼图的最后一部分现在通过中介管道发送此JObject。显然object instantiatedRequest无效。

有趣的是,我不需要知道Task<T> SendAsync<T>(IAsyncRequest<T> request)因为我会将其序列化为T以回复给用户。

签名string也可以用于当前的调解器框架以适应这种情况吗? (不要求它完成,只是可能吗?)

查看源代码

我在Task<object> SendAsync(object request)

中找到了这个
mediator.cs

第二个 private TWrapper GetHandler<TWrapper, TResponse>(object request, Type handlerType, Type wrapperType) { var requestType = request.GetType(); var genericHandlerType = _genericHandlerCache.GetOrAdd(requestType, handlerType, (type, root) => root.MakeGenericType(type, typeof(TResponse))); var genericWrapperType = _wrapperHandlerCache.GetOrAdd(requestType, wrapperType, (type, root) => root.MakeGenericType(type, typeof(TResponse))); var handler = GetHandler(request, genericHandlerType); return (TWrapper) Activator.CreateInstance(genericWrapperType, handler); } private object GetHandler(object request, Type handlerType) { try { return _singleInstanceFactory(handlerType); } catch (Exception e) { throw BuildException(request, e); } } 具有我需要的参数,第一个是GetHandler所调用的参数,我没有看到粘贴内容的问题。

有没有担心这样做?

2 个答案:

答案 0 :(得分:1)

这就是我从RabbitMqRequestHandler调用MediatR的方法。基本上,我想使用队列消息来触发任何命令类型。这一概念证明帮助我创建了另一个功能。

我们在这里:

private async Task HandleMessage(SmartConfigQueueMessage message)
{
    try
    {
        var type = AppDomain.CurrentDomain
            .GetAssemblies()
            .SelectMany(x => x.GetTypes())
            .FirstOrDefault(t => t.Name == message.OperationName);

        var resultType = type.GetInterfaces()
            .Where(r => r.FullName.Contains("SmartConfig"))? //MY ASSEMBLY MAIN NAMESPACE
            .FirstOrDefault().GenericTypeArguments
            .FirstOrDefault();

        dynamic command = message.Variables.ToObject(type);

        var method = _mediator.GetType().GetMethod("Send");
        var generic = method.MakeGenericMethod(resultType);
        var response = generic.InvokeAsync(_mediator, new object[] {command, new CancellationToken()});
    }
    catch (Exception ex)
    {
        _logger.LogInformation($"Consumer handler error: {ex.Message}");
    }

    // We just print this message   
    _logger.LogInformation($"Consumer message received: {message.OperationName}");
}

MediatR异步处理所有查询和命令。因此,我们需要此扩展名:

public static class GenericMethodExtensions
{
    public static async Task<object> InvokeAsync(this MethodInfo @this, object obj, params object[] parameters)
    {
        var task = (Task)@this.Invoke(obj, parameters);
        await task.ConfigureAwait(false);
        var resultProperty = task.GetType().GetProperty("Result");
        return resultProperty?.GetValue(task);
    }
} 

答案 1 :(得分:0)

所以有一种方法可以不修改源代码来实现这个目的:

var irequestInterface = typeof(GetCompanyRequest).GetInterfaces().FirstOrDefault(x => x.Name.StartsWith("IRequest"));

if (irequestInterface == null)
{
    throw new Exception("IRequest is null");
}

var tresponse = irequestInterface.GenericTypeArguments.FirstOrDefault();

if (tresponse == null)
{
    throw new Exception("Reponse is null");
}

var method = typeof(IMediator).GetMethod("Send");
var generic = method.MakeGenericMethod(tresponse);
generic.Invoke(mediator, new []{ (object)Activator.CreateInstance<GetCompanyRequest>() });

最后一位来自Jon Skeets answer

第一点是因为我们不关心TResponse因此我不想指定它。我们的GetCompanyRequest有足够的信息来执行SendAsync<TResponse>

通常我会厌倦使用反射,但我知道Mediator的实现使用了很多反思 - 所以你知道什么 - 我们只是将所有这些问题捆绑在一起。