C#网核巧妙简化Lambda表达式-更新

C#网核巧妙简化Lambda表达式-更新,c#,lambda,.net-core,autofac,masstransit,C#,Lambda,.net Core,Autofac,Masstransit,我正在寻找一个聪明的解决方案来简化一个越来越长的Lambda表达式。它看起来像这样: services.AddSingleton(provider => MassTransit.Bus.Factory.CreateUsingRabbitMq(cfg => { var host = cfg.Host("xyz", "/", hst => { hst.Username("user"); hst.Password("pass");

我正在寻找一个聪明的解决方案来简化一个越来越长的Lambda表达式。它看起来像这样:

services.AddSingleton(provider => MassTransit.Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    var host = cfg.Host("xyz", "/", hst =>
    {
        hst.Username("user");
        hst.Password("pass");
    });

    cfg.ReceiveEndpoint(host, "some_endp_1", e =>
    {
        e.LoadFrom(provider);
        EndpointConvention.Map<Class1>(e.InputAddress);
    });

    cfg.ReceiveEndpoint(host, "some_endp_2", e =>
    {
        e.LoadFrom(provider);
        EndpointConvention.Map<Class2>(e.InputAddress);
    });

    // ... a lot more of these here ....

    cfg.ReceiveEndpoint(host, "some_endp_n", e =>
    {
        e.LoadFrom(provider);
        EndpointConvention.Map<ClassN>(e.InputAddress);
    });
}));
services.AddSingleton(provider => MassTransit.Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    var host = cfg.Host("xyz", "/", hst =>
    {
        hst.Username("user");
        hst.Password("pass");
    });
    ConfigureEndPoint<Class1>(host, cfg, provider, "some_endp_1");
    ConfigureEndPoint<Class2>(host, cfg, provider, "some_endp_2");
    // ... a lot more of these here ...
    ConfigureEndPoint<Classn>(host, cfg, provider, "some_endp_n");        
}));
为什么不简单?每个使用者都继承了MassTransit.IConsumer,但这里的T要么是命令,要么是查询,命令从中继承一种接口类型,并查询一种完全不同的接口类型。因此,我真的不知道如何才能使这变得通用?也许把它分成两部分,一部分用于命令,一部分用于查询

我也不知道如何将
e.LoadFrom
正确更改为
e.Consumer(provider)因为我设置服务的方式在默认情况下与该调用不兼容

消费者在添加
.AddScoped
后也会添加到MassTransit中,例如:

services.AddMassTransit(x =>
{
    x.AddConsumer<MyConsumer1>();
    // the rest of the consumers all here, all added the same way                
});     
我相信有一个很好的解决方法可以使代码更短、更可读,但是你的想法是什么,我怎么做?如何将
e.LoadFrom
替换为
e.Consume()

谢谢,非常感谢社区和您的想法

更新2


我不确定我遗漏了什么-我的消费者都实现了来自MassTransit命名空间的IConsumer

免责声明:我对MassTransit一无所知-我以前从未使用过它,事实上,在阅读问题之前,我甚至从未听说过它

您可能应该检查一下,因为他建议使用MassTransit配置的另一种方式。(由于没有使用此工具的经验,我甚至不知道它是否更好,但这可能是您可以自己检查的。)

我的回答完全是从C#的角度出发的

首先想到的是创建一个方法来配置
ReceiveEndpoint
——类似这样的(我不知道涉及的类型,您可能需要更改它们):

void ConfigureEndPoint(主机、配置cfg、提供程序、字符串endPointName)
{
ReceiveEndpoint(主机,endPointName,e=>
{
e、 从(供应商)处下载;
EndpointConvention.Map(例如输入地址);
}
}
然后,在lambda表达式中,您可以这样使用它:

services.AddSingleton(provider => MassTransit.Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    var host = cfg.Host("xyz", "/", hst =>
    {
        hst.Username("user");
        hst.Password("pass");
    });

    cfg.ReceiveEndpoint(host, "some_endp_1", e =>
    {
        e.LoadFrom(provider);
        EndpointConvention.Map<Class1>(e.InputAddress);
    });

    cfg.ReceiveEndpoint(host, "some_endp_2", e =>
    {
        e.LoadFrom(provider);
        EndpointConvention.Map<Class2>(e.InputAddress);
    });

    // ... a lot more of these here ....

    cfg.ReceiveEndpoint(host, "some_endp_n", e =>
    {
        e.LoadFrom(provider);
        EndpointConvention.Map<ClassN>(e.InputAddress);
    });
}));
services.AddSingleton(provider => MassTransit.Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    var host = cfg.Host("xyz", "/", hst =>
    {
        hst.Username("user");
        hst.Password("pass");
    });
    ConfigureEndPoint<Class1>(host, cfg, provider, "some_endp_1");
    ConfigureEndPoint<Class2>(host, cfg, provider, "some_endp_2");
    // ... a lot more of these here ...
    ConfigureEndPoint<Classn>(host, cfg, provider, "some_endp_n");        
}));
services.AddSingleton(provider=>MassTransit.Bus.Factory.CreateUsingRabbitMq(cfg=>
{
var host=cfg.host(“xyz”,“/”,hst=>
{
hst.用户名(“用户”);
密码(“通行证”);
});
ConfigureEndPoint(主机、cfg、提供程序、“某些端点”1);
ConfigureEndPoint(主机、cfg、提供程序、“某些端点”2);
//…这里有很多这样的。。。
配置端点(主机、cfg、提供程序、“某些端点”);
}));

假设:我的答案假设
.Map()
有一个重载,它采用
类型而不是
通用的
(例如
.Map(typeof(Class1),例如InputAddress)
),因为这在此类通用函数中非常常见

如果不是这样的话,那么就忽略这个答案。我觉得这对其他处于类似情况的人来说仍然是有用的


您似乎误解了端点、消费者和约定的概念

我非常担心您对每个端点使用
LoadFrom
。这意味着在容器中注册的所有消费者都将在每个端点中侦听

通常,如果您希望按端点拆分使用者,则需要通过调用
ep.Consumer(provider)
显式配置端点

解决方案2:

如果要使用每个端点一个使用者来分离使用者,并使用类似于单线端点配置的配置,可以使用以下代码轻松完成:

using System;
using MassTransit.RabbitMqTransport;

namespace MassTransit.TestCode
{
    public static class BusConfigurationExtensions
    {
        public static void ConfigureEndpoint<T>(this IRabbitMqBusFactoryConfigurator cfg,
            IRabbitMqHost host, string endpointName, IServiceProvider provider)
        where T : class, IConsumer
            => cfg.ReceiveEndpoint(host, endpointName, ep => ep.Consumer<T>(provider));
    }
}
在我的第一个代码片段中,我使用了方法组,这并不意味着您不能只使用表达式lambda

在下一个版本中将有一个新的包
MassTransit.AspNetCore
,以便更好地将MassTransit与ASP.NET Core集成。它将配置总线主机,正确注册总线实例,并应用日志记录。配置将如下所示(此代码有效,我刚刚编写并测试了它):

public void配置服务(IServiceCollection服务)
{
services.AddMassTransit(provider=>Bus.Factory.CreateUsingRabbitMq(cfg=>
{
var host=cfg.host(新Uri(“rabbitmq://localhost,h=>
{
h、 用户名(“客人”);
h、 密码(“客人”);
});
ReceiveEndpoint(主机,“message_one”,ep=>ep.Consumer(提供者));
ReceiveEndpoint(主机,“message_two”,ep=>ep.Consumer(提供者));
}));
}

请记住,每个端点都有自己的队列。如果您刚刚开始工作并想尝试一些东西,您可以选择第一个解决方案,这样您将有一个队列。随着时间的推移,您可以拆分端点。

EndpointConvention.Map(mappingType,e.InputAddress)
不起作用-该方法的非泛型方法不将类型作为参数。这将使事情变得更简单:-)此方法不适用于MassTransit及其设置方式。虽然它在语法上是正确的(我调整了void ConfigureEndPoint以匹配类型),但它也可以编译和运行。但是,它在第一次尝试调用链接到此的API终结点时崩溃。同时,原始代码(不使用其他帮助程序方法)正如预期的那样完美工作。“它在第一次尝试调用链接到此的API终结点时崩溃。”我从未使用过MassTransit,但是,当它崩溃时,您得到的错误消息可能会帮助您找出错误所在……而且,实际上,不要使用.LoadFrom()——特别是当多个接收端点与单个提供程序同时存在时。你到处都在消费。请看下面Alexey的答案
services.AddSingleton(provider => MassTransit.Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    var host = cfg.Host("xyz", "/", hst =>
    {
        hst.Username("user");
        hst.Password("pass");
    });
    ConfigureEndPoint<Class1>(host, cfg, provider, "some_endp_1");
    ConfigureEndPoint<Class2>(host, cfg, provider, "some_endp_2");
    // ... a lot more of these here ...
    ConfigureEndPoint<Classn>(host, cfg, provider, "some_endp_n");        
}));
services.AddSingleton(provider => MassTransit.Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    var host = cfg.Host("xyz", "/", hst =>
    {
        hst.Username("user");
        hst.Password("pass");
    });

    var mappingTypes = new Type[] { typeof(Class1), typeof(Class2), ... etc };
    foreach (var mappingType in mappingTypes)
    {
        // I did mappingType.Name for simplicity, but you could get the mappingType's index in the collection and use that as well if you need this to be a number.
        cfg.ReceiveEndpoint(host, "some_endp_" + mappingType.Name, e =>
        {
            e.LoadFrom(provider);
            // See note at the top of answer.
            EndpointConvention.Map(mappingType, e.InputAddress);
        });
    }

}));
cfg.ReceiveEndpoint(host, "some_endp_2", e =>
{
    e.Consumer<SomeConsumer>(provider);
});
cfg.ReceiveEndpoint(host, "some_endp_2", e =>
{
    e.Consumer<SomeOtherConsumer>(provider);
});
cfg.ReceiveEndpoint(host, "my_service", e =>
{
    e.LoadFrom(provider);
});
using System;
using MassTransit.RabbitMqTransport;

namespace MassTransit.TestCode
{
    public static class BusConfigurationExtensions
    {
        public static void ConfigureEndpoint<T>(this IRabbitMqBusFactoryConfigurator cfg,
            IRabbitMqHost host, string endpointName, IServiceProvider provider)
        where T : class, IConsumer
            => cfg.ReceiveEndpoint(host, endpointName, ep => ep.Consumer<T>(provider));
    }
}
cfg.ConfigureEndpoint<SubmitOrderConsumer>(host, "submit_order", provider);
cfg.ConfigureEndpoint<MarkOrderAsPaidConsumer>(host, "mark_paid", provider);
cfg.ConfigureEndpoint<ShipOrderConsumer>(host, "ship_order", provider);
cfg.ReceiveEndpoint(host, endpointName, ep => ep.Consumer<SubmitOrderConsumer>(provider));
cfg.ReceiveEndpoint(host, endpointName, ep => ep.Consumer<MarkOrderAsPaidConsumer>(provider));
cfg.ReceiveEndpoint(host, endpointName, ep => ep.Consumer<ShipOrderConsumer>(provider));
public void ConfigureServices(IServiceCollection services)
{
    services.AddMassTransit(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
    {
        var host = cfg.Host(new Uri("rabbitmq://localhost"), h =>
        {
            h.Username("guest");
            h.Password("guest");
        });
        cfg.ReceiveEndpoint(host, "message_one", ep => ep.Consumer<MessageOneConsumer>(provider));
        cfg.ReceiveEndpoint(host, "message_two", ep => ep.Consumer<MessageTwoConsumer>(provider));
    }));
}