[英]Injecting objects into a MassTransit Saga using Autofac
I'm trying to get autofac to inject an factory into a saga on creation, and I can't get it working. 我正试图让autofac将一个工厂注入创造的传奇,我无法让它工作。 I've had no problem injecting the factory into a consumer so I know it's registered correctly, so I'm assuming I'm not registering the sagas correctly and autofac isn't building them up. 我没有把工厂注入消费者的问题所以我知道它已正确注册,所以我假设我没有正确注册传真,而autofac也没有建立它们。
Here's my registration code: 这是我的注册码:
var mapTypes = assembly.GetTypes()
.Where(type => type.Implements(typeof(SagaClassMapping<>)));
builder.Register(context => GetSessionFactory(mapTypes)).AsSelf().SingleInstance();
// register all sagas and consumers
builder.RegisterAssemblyTypes(assembly)
.Where(type => type.IsAssignableTo<ISaga>() || type.IsAssignableTo<IConsumer>())
.AsSelf();
builder
.RegisterGeneric(typeof(NHibernateSagaRepository<>))
.As(typeof(ISagaRepository<>))
.SingleInstance();
builder
.Register(context => ServiceBusFactory.New(sbc =>
{
sbc.UseLog4Net();
var queueUri = new Uri(ConfigurationManager.AppSettings["ReceiveQueue"]);
var scope = context.Resolve<ILifetimeScope>();
sbc.UseRabbitMq(transportConfig =>
transportConfig.ConfigureHost(queueUri, hostConfig =>
{
hostConfig.SetUsername(ConfigurationManager.AppSettings["busUser"]);
hostConfig.SetPassword(ConfigurationManager.AppSettings["busPassword"]);
}));
sbc.ReceiveFrom(queueUri);
sbc.Subscribe(cfg => cfg.LoadFrom(scope));
}))
.SingleInstance();
The saga itself is pretty standard 传奇本身非常标准
public class MySaga : SagaStateMachine<MySaga>, ISaga
{
public Guid CorrelationId { get; private set; }
public Func<MyObject> ObjectBuilder { get; set; }
public MySaga() { }
public MySaga(Guid correlationId)
{
CorrelationId = correlationId;
}
Static MySaga()
{
Define(() =>
{ .... }
}
I've tried adding the Func<MyObject>
to a constructor, but it's not hit, it does work in a consumer so I know Autofac can build a Func<MyObject>
. 我已经尝试将Func<MyObject>
添加到构造函数中,但它没有被命中,它确实在消费者中工作,所以我知道Autofac可以构建一个Func<MyObject>
。 I also tried using property injection with no luck: 我也尝试过使用属性注入而没有运气:
builder.RegisterAssemblyTypes(assembly)
.Where(type => type.IsAssignableTo<ISaga>() || type.IsAssignableTo<IConsumer>())
.PropertiesAutowired()
.AsSelf();
and 和
builder.RegisterType<MySaga>()
.OnActivated(arg => arg.Instance.MyBuilder =
arg.Context.Resolve<Func<MyObject>>())
.AsSelf();
Any help on what I'm doing wrong would be appreciated. 对我所做错的任何帮助都将不胜感激。
I got a reply from Chris Patterson on the masstransit-discuss group that pointed out I was probably doing it wrong. 我得到了Chris Patterson对masstransit-discuss小组的回复,指出我可能做错了。
Automatonymous is a better choice if you have dependencies, since the state machine and the state itself are separate classes. 如果你有依赖关系,Automatonymous是一个更好的选择,因为状态机和状态本身是单独的类。
Injecting dependencies into a class hydrated via NHibernate is never going to end well. 通过NHibernate将依赖关系注入到水合中的类永远不会结束。 There are a couple of helper classes that can be used to perform property-injection into the saga after it is loaded from NHibernate, the decorating saga repository I think has been posted here. 从NHibernate加载后,有几个辅助类可用于执行属性注入到saga中,我认为装饰传奇存储库已在此处发布。
Here is the example of the injecting repository for Magnum: https://github.com/MassTransit/MassTransit/blob/master/src/MassTransit.Tests/Saga/Injecting_Specs.cs 以下是Magnum注入存储库的示例: https : //github.com/MassTransit/MassTransit/blob/master/src/MassTransit.Tests/Saga/Injecting_Specs.cs
Given it's NHibernate that's hydrating the object I should be looking there for the hook. 鉴于它的NHibernate正在保护物体,我应该在那里寻找钩子。 I've got a workaround for my current issue, but I'll post an answer here if/when I find one. 我的当前问题有一个解决方法,但如果/当我找到一个,我会在这里发布一个答案。
old question but it took a while for us to figure out a suitable way to wiring up sagas and autofac and then adding nhibernate on top of that. 旧的问题,但我们花了一段时间才找到一个合适的方法来连接传奇和autofac,然后添加nhibernate。
First create a wiring class (property injection) 首先创建一个布线类(属性注入)
public class MySagaRepository<TSaga> : ISagaRepository<TSaga> where TSaga : class, ISaga
{
private ISagaRepository<TSaga> _inner;
private readonly IComponentContext _context;
public MySagaRepository(ISagaRepository<TSaga> inner, IComponentContext context)
{
_inner = inner;
_context = context;
}
public IEnumerable<Action<IConsumeContext<TMessage>>> GetSaga<TMessage>(IConsumeContext<TMessage> context, Guid sagaId, InstanceHandlerSelector<TSaga, TMessage> selector, ISagaPolicy<TSaga, TMessage> policy) where TMessage : class
{
return _inner.GetSaga(context, sagaId, (saga, message) =>
{
_context.InjectProperties(saga);
return selector(saga, message);
}, policy);
}
public IEnumerable<Guid> Find(ISagaFilter<TSaga> filter)
{
return _inner.Find(filter);
}
public IEnumerable<TSaga> Where(ISagaFilter<TSaga> filter)
{
return _inner.Where(filter).Select(x =>
{
_context.InjectProperties<TSaga>(x);
return x;
});
}
public IEnumerable<TResult> Where<TResult>(ISagaFilter<TSaga> filter, Func<TSaga, TResult> transformer)
{
return _inner.Where(filter, x =>
{
_context.InjectProperties(x);
return transformer(x);
});
}
public IEnumerable<TResult> Select<TResult>(Func<TSaga, TResult> transformer)
{
return _inner.Select(x =>
{
_context.InjectProperties(x);
return transformer(x);
});
}
}
Then wire it 然后连线
builder.RegisterGeneric(typeof(NHibernateSagaRepository<>)).Named("innerRepo", typeof(ISagaRepository<>));
builder.RegisterGenericDecorator(typeof(MySagaRepository<>), typeof(ISagaRepository<>), fromKey: "innerRepo");
For the persistance it was just a matter of 对于持久性而言,这只是一个问题
public class SagaPersistenceHandler
{
public static ISessionFactory CreateSessionFactory()
{
var provider = new SqlServerSessionFactoryProvider(ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString, new[]
{
typeof (MySagaMap)
});
return provider.GetSessionFactory();
}
}
Now wire that 现在连线
builder.Register(c => SagaPersistenceHandler.CreateSessionFactory()).As<ISessionFactory>();
and the saga mapping to the saga (not included) 和传奇映射到传奇(不包括在内)
public MySagaMap()
{
SchemaAction(NHibernate.Mapping.ByCode.SchemaAction.None);
Table("dbo.[tTable]");
Property(x => x.Id);
Property(x => x.CloseDate);
}
}
All thats left is to register your saga 剩下的就是注册你的传奇
builder.RegisterType<MySaga>().AsSelf();
worked well (credits goes to @erikkallen) 工作得很好(学分归@erikkallen)
I made an adapter for Autofac to register and configure MT state machine sagas. 我为Autofac制作了一个适配器来注册和配置MT状态机传奇。
It is available on nuget.org. 它可以在nuget.org上找到。
You can register your consumers and state machines by calling: 您可以通过以下方式注册您的消费者和州机器:
builder.RegisterSagaStateMachines(sagasAssembly); // register all state machines
builder.RegisterConsumers(consumersAssembly); // register consumers (standard MassTransit Autofac integration)
Note that RegisterConsumers
is the standard MassTransit.Autofac
extension. 请注意, RegisterConsumers
是标准的MassTransit.Autofac
扩展。
In your endpoint configuration you need to call the configuration like this: 在端点配置中,您需要调用以下配置:
x.ReceiveEndpoint(queueName, c =>
{
c.LoadConsumers(container);
c.LoadStateMachineSagas(container);
});
Pre-condition is that you have to register ISagaRepository
implementations as well. 前提条件是您还必须注册ISagaRepository
实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.