2

如果我发送 HTTP Get 请求:

/api/Company/1

我有一个OwinMiddleware我正在使用的地方context来确定path一个IAsyncRequest<T>.

要知道要使用哪个异步请求,我有一个路径映射TypeIAsyncRequest<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);

我使用的原因JObject是对于 PUT 和 POST 请求,我将 JSON 正文直接反序列化为请求。

现在拼图的最后一块是object instantiatedRequest通过中介管道发送它。显然Task<T> SendAsync<T>(IAsyncRequest<T> request)行不通。

有趣的是,我不需要知道T,因为我将始终将其序列化为 astring以发回给用户。

那么签名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有我需要的参数,第一个是 by 调用的参数SendAsync,我认为插入一些东西没有问题。

这样做有什么顾虑吗?

4

2 回答 2

1

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

重要提示:这适用于 (MediatR 7.0.0) 我的功能在升级到版本 9 时停止工作。

开始了:

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);
    }
} 
于 2020-08-25T12:08:12.687 回答
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 的回答

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

通常我会厌倦使用反射,但我知道实现会Mediator使用大量反射——所以你知道吗——我们将把所有这些问题捆绑在一起。

于 2016-06-28T15:42:10.633 回答