C#网核巧妙简化Lambda表达式-更新
我正在寻找一个聪明的解决方案来简化一个越来越长的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");
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));
}));
}