Azure 服务结构参与者依赖注入
Azure service fabric actor dependency injection
有什么方法可以将依赖项注入到 Azure Service Fabric Actor 的构造函数中吗?
不久前使用 dotPeek 在这个领域进行了一些研究(尝试在每次调用时从 Autofac 生命周期范围解析参与者),我认为诀窍是创建您自己的 StatelessActorServiceFactory 实现,和你自己的扩展方法来注册演员。虽然工厂class被标记为内部,但它的接口(IStatelessServiceFactory)和它创建的服务类型(StatelessActorServiceInstance)都是public。不幸的是,StatelessActorServiceInstance 看起来并不是设计为可扩展的(我希望这只是一个疏忽)。
不幸的是,WcfActorCommunicationProvider 似乎也被标记为内部的,因此您几乎必须从头开始创建自己的管道:
- 实现你自己的 IStatelessServiceFactory
- 实现你自己的 IStatelessServiceInstance, IActorService
- 实现你自己的 IActorCommunicationProvider
- 实现你自己的 IActorHost
似乎不再值得付出努力了,是吗? :-/
那是我暂时放弃的地方。考虑到 public API 的相对不成熟,我认为现在不值得尝试自己动手,因为如果这种功能完全出现,他们可能会这样做所以在某种程度上会破坏你自己实现的任何东西。
为什么不直接在 actor 中使用一些根元素字段,并在 Actor 的构造函数中从具有注入依赖项的容器中解析它?如果这是一个错误的决定,请解释原因:
public class StatelessActor2 : Actor, IStatelessActor2
{
private ConfiguredContainer _container;
private IRootElement _rootElement;
public StatelessActor2()
{
_container = new ConfiguredContainer(); //... container is configured in it's constructor
_rootElement = _container.Resolve<IRootElement>();
}
public async Task<string> DoWorkAsync()
{
// Working with a RootElement with all dependencies are injected..
return await Task.FromResult(_rootElement.WorkingWithInjectedStuff());
}
}
我知道这已经过时了,但是出于文档的考虑,现在 Reliable Actor 框架中支持 DI,正如您所期望的那样。
public class ActorOne : Actor<MyActorState>, IMyActor{
private readonly IDependency _dependency;
public ActorOne(IDependency dependency)
{
_dependency = dependency;
}}
然后将 Actor 及其依赖项注册到 Service Fabric,如下所示:
using (FabricRuntime fRuntime = FabricRuntime.Create()){
fRuntime.RegisterActor(() => new ActorOne(new MyDependency());
Thread.Sleep(Timeout.Infinite);}
已更新
一切都在 github 上,我现在得到:https://github.com/s-innovations/S-Innovations.ServiceFabric.Unity
并轻松与 aspnet 核心依赖注入集成,查看 readme.md
的示例
我是 Unity 的长期用户,并决定制作核心扩展方法,以便在与演员合作时获得良好的依赖注入体验。
我的 program.cs 现在看起来像这样:
internal static class Program
{
/// <summary>
/// This is the entry point of the service host process.
/// </summary>
private static void Main()
{
try
{
using (var container = new UnityContainer())
{
container.RegisterType<IMessageProcessorClientFactory, DummyFactory>(new HierarchicalLifetimeManager());
container.RegisterType<IMessageClusterConfigurationStore, test>(new HierarchicalLifetimeManager());
container.WithFabricContainer();
container.WithActor<MessageClusterActor>();
container.WithActor<QueueListenerActor>();
container.WithStatelessFactory<ManagementApiServiceFactory>("ManagementApiServiceType");
container.WithActor<VmssManagerActor>();
ServiceFabricEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(ManagementApiService).Name);
Thread.Sleep(Timeout.Infinite); // Prevents this host process from terminating to keep the service host process running.
}
}
catch (Exception e)
{
ServiceFabricEventSource.Current.ActorHostInitializationFailed(e.ToString());
throw;
}
}
}
我在 actors 和服务中的位置可以在构造函数中放入我的依赖项。
public class VmssManagerActor : StatefulActor<VmssManagerActor.ActorState>, IVmssManagerActor, IRemindable
{
public const string CheckProvision = "CheckProvision";
/// <summary>
/// Cluster Configuration Store
/// </summary>
protected IMessageClusterConfigurationStore ClusterConfigStore { get; private set; }
public VmssManagerActor(IMessageClusterConfigurationStore clusterProvider)
{
ClusterConfigStore = clusterProvider;
}
如果您觉得这很有用并且希望我将其放入 nuget 包中,请为这个答案点赞。
关于实现的一个注意事项,每个参与者都会有自己的范围。这意味着所有在 'HierarchicalLifetimeManager' 注册并实现 IDisposable
的依赖项将自动在 actor OnDeactivationAsync
中释放。这是通过使用动态类型动态代理参与者 class 来完成的,该动态类型拦截对 OnDeactivationAsync
的调用。为此,必须 public 定义 Actor。
IActorDeactivationInterception.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Abstraction
{
/// <summary>
/// The <see cref="IActorDeactivationInterception"/> interface for defining an OnDeactivateInterception
/// </summary>
public interface IActorDeactivationInterception
{
void Intercept();
}
}
ActorProxyTypeFactory.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Actors
{
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
public class ActorProxyTypeFactory
{
/// <summary>
/// Creates a new instance of the <see cref="ActorProxyTypeFactory"/> class.
/// </summary>
/// <param name="target"></param>
public ActorProxyTypeFactory(Type target)
{
this.target = target;
}
/// <summary>
/// Creates the proxy registered with specific interceptor.
/// </summary>
/// <returns></returns>
public static T Create<T>(IActorDeactivationInterception deactivation, params object[] args)
{
return (T)new ActorProxyTypeFactory(typeof(T)).Create(new object[] { deactivation }.Concat(args).ToArray());
}
public static Type CreateType<T>()
{
return new ActorProxyTypeFactory(typeof(T)).CreateType();
}
/// <summary>
/// Creates the proxy registered with specific interceptor.
/// </summary>
/// <returns></returns>
public object Create(object[] args)
{
BuidAssembly();
BuildType();
InterceptAllMethods();
Type proxy = this.typeBuilder.CreateType();
return Activator.CreateInstance(proxy, args);
}
public Type CreateType()
{
BuidAssembly();
BuildType();
InterceptAllMethods();
Type proxy = this.typeBuilder.CreateType();
return proxy;
// return Activator.CreateInstance(proxy, args);
}
/// <summary>
/// Builds a dynamic assembly with <see cref="AssemblyBuilderAccess.RunAndSave"/> mode.
/// </summary>
/// <returns></returns>
public void BuidAssembly()
{
AssemblyName assemblyName = new AssemblyName("BasicProxy");
AssemblyBuilder createdAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
// define module
this.moduleBuilder = createdAssembly.DefineDynamicModule(assemblyName.Name);
}
public void BuildType()
{
if (!target.IsPublic)
{
throw new ArgumentException("Actors have to be public defined to proxy them");
}
this.typeBuilder =
this.moduleBuilder.DefineType(target.FullName + "Proxy", TypeAttributes.Class | TypeAttributes.Public, target);
this.fldInterceptor = this.typeBuilder.DefineField("interceptor", typeof(IActorDeactivationInterception), FieldAttributes.Private);
foreach (var constructor in target.GetConstructors())
{
// Type[] parameters = new Type[1];
ParameterInfo[] parameterInfos = constructor.GetParameters();
Type[] parameters = new Type[parameterInfos.Length + 1];
parameters[0] = typeof(IActorDeactivationInterception);
for (int index = 1; index <= parameterInfos.Length; index++)
{
parameters[index] = parameterInfos[index - 1].ParameterType;
}
ConstructorBuilder constructorBuilder =
typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, parameters);
for (int argumentIndex = 0; argumentIndex < parameters.Length; argumentIndex++)
constructorBuilder.DefineParameter(
argumentIndex + 1,
ParameterAttributes.None,
$"arg{argumentIndex}");
ILGenerator generator = constructorBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
for (int index = 1; index < parameters.Length; index++)
{
generator.Emit(OpCodes.Ldarg, index + 1);
}
generator.Emit(OpCodes.Call, constructor);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, fldInterceptor);
generator.Emit(OpCodes.Ret);
}
}
/// <summary>
/// Builds a type in the dynamic assembly, if already the type is not created.
/// </summary>
/// <returns></returns>
public void InterceptAllMethods()
{
const MethodAttributes targetMethodAttributes =
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig;
var methodInfo = target.GetMethod("OnDeactivateAsync", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
{
if (methodInfo.IsVirtual)
{
Type[] paramTypes = GetParameterTypes(methodInfo.GetParameters());
MethodBuilder methodBuilder =
typeBuilder.DefineMethod(methodInfo.Name, targetMethodAttributes, methodInfo.ReturnType, paramTypes);
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, fldInterceptor);
ilGenerator.Emit(OpCodes.Call, typeof(IActorDeactivationInterception).GetMethod("Intercept"));
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Call, methodInfo);
ilGenerator.Emit(OpCodes.Ret);
return;
}
}
}
private Type[] GetParameterTypes(ParameterInfo[] parameterInfos)
{
Type[] parameters = new Type[parameterInfos.Length];
int index = 0;
foreach (var parameterInfo in parameterInfos)
{
parameters[index++] = parameterInfo.ParameterType;
}
return parameters;
}
private TypeBuilder typeBuilder;
private ModuleBuilder moduleBuilder;
private readonly Type target;
private FieldInfo fldInterceptor;
}
}
OnActorDeactivateInterceptor.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Actors
{
using Microsoft.Practices.Unity;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
public class OnActorDeactivateInterceptor : IActorDeactivationInterception
{
private readonly IUnityContainer container;
public OnActorDeactivateInterceptor(IUnityContainer container)
{
this.container = container;
}
public void Intercept()
{
this.container.Dispose();
}
}
}
UnityFabricExtensions.cs
namespace SInnovations.Azure.ServiceFabric.Unity
{
using System;
using System.Fabric;
using Microsoft.Practices.Unity;
using Microsoft.ServiceFabric.Actors;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
using SInnovations.Azure.ServiceFabric.Unity.Actors;
public static class UnityFabricExtensions
{
public static IUnityContainer WithFabricContainer(this IUnityContainer container)
{
return container.WithFabricContainer(c => FabricRuntime.Create());
}
public static IUnityContainer WithFabricContainer(this IUnityContainer container, Func<IUnityContainer,FabricRuntime> factory)
{
container.RegisterType<FabricRuntime>(new ContainerControlledLifetimeManager(), new InjectionFactory(factory));
return container;
}
public static IUnityContainer WithActor<TActor>(this IUnityContainer container) where TActor : ActorBase
{
if (!container.IsRegistered<IActorDeactivationInterception>())
{
container.RegisterType<IActorDeactivationInterception, OnActorDeactivateInterceptor>(new HierarchicalLifetimeManager());
}
container.RegisterType(typeof(TActor), ActorProxyTypeFactory.CreateType<TActor>(),new HierarchicalLifetimeManager());
container.Resolve<FabricRuntime>().RegisterActorFactory(() => {
try {
var actor = container.CreateChildContainer().Resolve<TActor>();
return actor;
}
catch (Exception ex)
{
throw;
}
});
return container;
}
public static IUnityContainer WithStatelessFactory<TFactory>(this IUnityContainer container, string serviceTypeName) where TFactory : IStatelessServiceFactory
{
if (!container.IsRegistered<TFactory>())
{
container.RegisterType<TFactory>(new ContainerControlledLifetimeManager());
}
container.Resolve<FabricRuntime>().RegisterStatelessServiceFactory(serviceTypeName, container.Resolve<TFactory>());
return container;
}
public static IUnityContainer WithStatefulFactory<TFactory>(this IUnityContainer container, string serviceTypeName) where TFactory : IStatefulServiceFactory
{
if (!container.IsRegistered<TFactory>())
{
container.RegisterType<TFactory>(new ContainerControlledLifetimeManager());
}
container.Resolve<FabricRuntime>().RegisterStatefulServiceFactory(serviceTypeName, container.Resolve<TFactory>());
return container;
}
public static IUnityContainer WithService<TService>(this IUnityContainer container, string serviceTypeName)
{
container.Resolve<FabricRuntime>().RegisterServiceType(serviceTypeName, typeof(TService));
return container;
}
}
}
如果您使用的是 Autofac,他们有专门的集成包:
https://alexmg.com/introducing-the-autofac-integration-for-service-fabric/
https://www.nuget.org/packages/Autofac.ServiceFabric/
简而言之,如您所料,使用 ActorRuntime.RegisterActorAsync
/ ServiceRuntime.RegisterServiceAsync
进行注册。然而,更有问题的部分,即对象释放,在 OnDeactivateAsync
/ OnCloseAsync
/ OnAbort
覆盖中使用动态代理自动处理。适当的生命周期范围也得到维护。
在撰写本文时,它仍处于 Alpha 阶段(上个月刚刚发布)。
@abatishchev 我认为你指的是 Service-Locator 反模式。依赖注入和 Service-Locator 都是控制反转的变体。
有什么方法可以将依赖项注入到 Azure Service Fabric Actor 的构造函数中吗?
不久前使用 dotPeek 在这个领域进行了一些研究(尝试在每次调用时从 Autofac 生命周期范围解析参与者),我认为诀窍是创建您自己的 StatelessActorServiceFactory 实现,和你自己的扩展方法来注册演员。虽然工厂class被标记为内部,但它的接口(IStatelessServiceFactory)和它创建的服务类型(StatelessActorServiceInstance)都是public。不幸的是,StatelessActorServiceInstance 看起来并不是设计为可扩展的(我希望这只是一个疏忽)。
不幸的是,WcfActorCommunicationProvider 似乎也被标记为内部的,因此您几乎必须从头开始创建自己的管道:
- 实现你自己的 IStatelessServiceFactory
- 实现你自己的 IStatelessServiceInstance, IActorService
- 实现你自己的 IActorCommunicationProvider
- 实现你自己的 IActorHost
似乎不再值得付出努力了,是吗? :-/
那是我暂时放弃的地方。考虑到 public API 的相对不成熟,我认为现在不值得尝试自己动手,因为如果这种功能完全出现,他们可能会这样做所以在某种程度上会破坏你自己实现的任何东西。
为什么不直接在 actor 中使用一些根元素字段,并在 Actor 的构造函数中从具有注入依赖项的容器中解析它?如果这是一个错误的决定,请解释原因:
public class StatelessActor2 : Actor, IStatelessActor2
{
private ConfiguredContainer _container;
private IRootElement _rootElement;
public StatelessActor2()
{
_container = new ConfiguredContainer(); //... container is configured in it's constructor
_rootElement = _container.Resolve<IRootElement>();
}
public async Task<string> DoWorkAsync()
{
// Working with a RootElement with all dependencies are injected..
return await Task.FromResult(_rootElement.WorkingWithInjectedStuff());
}
}
我知道这已经过时了,但是出于文档的考虑,现在 Reliable Actor 框架中支持 DI,正如您所期望的那样。
public class ActorOne : Actor<MyActorState>, IMyActor{
private readonly IDependency _dependency;
public ActorOne(IDependency dependency)
{
_dependency = dependency;
}}
然后将 Actor 及其依赖项注册到 Service Fabric,如下所示:
using (FabricRuntime fRuntime = FabricRuntime.Create()){
fRuntime.RegisterActor(() => new ActorOne(new MyDependency());
Thread.Sleep(Timeout.Infinite);}
已更新
一切都在 github 上,我现在得到:https://github.com/s-innovations/S-Innovations.ServiceFabric.Unity
并轻松与 aspnet 核心依赖注入集成,查看 readme.md
的示例我是 Unity 的长期用户,并决定制作核心扩展方法,以便在与演员合作时获得良好的依赖注入体验。
我的 program.cs 现在看起来像这样:
internal static class Program
{
/// <summary>
/// This is the entry point of the service host process.
/// </summary>
private static void Main()
{
try
{
using (var container = new UnityContainer())
{
container.RegisterType<IMessageProcessorClientFactory, DummyFactory>(new HierarchicalLifetimeManager());
container.RegisterType<IMessageClusterConfigurationStore, test>(new HierarchicalLifetimeManager());
container.WithFabricContainer();
container.WithActor<MessageClusterActor>();
container.WithActor<QueueListenerActor>();
container.WithStatelessFactory<ManagementApiServiceFactory>("ManagementApiServiceType");
container.WithActor<VmssManagerActor>();
ServiceFabricEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(ManagementApiService).Name);
Thread.Sleep(Timeout.Infinite); // Prevents this host process from terminating to keep the service host process running.
}
}
catch (Exception e)
{
ServiceFabricEventSource.Current.ActorHostInitializationFailed(e.ToString());
throw;
}
}
}
我在 actors 和服务中的位置可以在构造函数中放入我的依赖项。
public class VmssManagerActor : StatefulActor<VmssManagerActor.ActorState>, IVmssManagerActor, IRemindable
{
public const string CheckProvision = "CheckProvision";
/// <summary>
/// Cluster Configuration Store
/// </summary>
protected IMessageClusterConfigurationStore ClusterConfigStore { get; private set; }
public VmssManagerActor(IMessageClusterConfigurationStore clusterProvider)
{
ClusterConfigStore = clusterProvider;
}
如果您觉得这很有用并且希望我将其放入 nuget 包中,请为这个答案点赞。
关于实现的一个注意事项,每个参与者都会有自己的范围。这意味着所有在 'HierarchicalLifetimeManager' 注册并实现 IDisposable
的依赖项将自动在 actor OnDeactivationAsync
中释放。这是通过使用动态类型动态代理参与者 class 来完成的,该动态类型拦截对 OnDeactivationAsync
的调用。为此,必须 public 定义 Actor。
IActorDeactivationInterception.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Abstraction
{
/// <summary>
/// The <see cref="IActorDeactivationInterception"/> interface for defining an OnDeactivateInterception
/// </summary>
public interface IActorDeactivationInterception
{
void Intercept();
}
}
ActorProxyTypeFactory.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Actors
{
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
public class ActorProxyTypeFactory
{
/// <summary>
/// Creates a new instance of the <see cref="ActorProxyTypeFactory"/> class.
/// </summary>
/// <param name="target"></param>
public ActorProxyTypeFactory(Type target)
{
this.target = target;
}
/// <summary>
/// Creates the proxy registered with specific interceptor.
/// </summary>
/// <returns></returns>
public static T Create<T>(IActorDeactivationInterception deactivation, params object[] args)
{
return (T)new ActorProxyTypeFactory(typeof(T)).Create(new object[] { deactivation }.Concat(args).ToArray());
}
public static Type CreateType<T>()
{
return new ActorProxyTypeFactory(typeof(T)).CreateType();
}
/// <summary>
/// Creates the proxy registered with specific interceptor.
/// </summary>
/// <returns></returns>
public object Create(object[] args)
{
BuidAssembly();
BuildType();
InterceptAllMethods();
Type proxy = this.typeBuilder.CreateType();
return Activator.CreateInstance(proxy, args);
}
public Type CreateType()
{
BuidAssembly();
BuildType();
InterceptAllMethods();
Type proxy = this.typeBuilder.CreateType();
return proxy;
// return Activator.CreateInstance(proxy, args);
}
/// <summary>
/// Builds a dynamic assembly with <see cref="AssemblyBuilderAccess.RunAndSave"/> mode.
/// </summary>
/// <returns></returns>
public void BuidAssembly()
{
AssemblyName assemblyName = new AssemblyName("BasicProxy");
AssemblyBuilder createdAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
// define module
this.moduleBuilder = createdAssembly.DefineDynamicModule(assemblyName.Name);
}
public void BuildType()
{
if (!target.IsPublic)
{
throw new ArgumentException("Actors have to be public defined to proxy them");
}
this.typeBuilder =
this.moduleBuilder.DefineType(target.FullName + "Proxy", TypeAttributes.Class | TypeAttributes.Public, target);
this.fldInterceptor = this.typeBuilder.DefineField("interceptor", typeof(IActorDeactivationInterception), FieldAttributes.Private);
foreach (var constructor in target.GetConstructors())
{
// Type[] parameters = new Type[1];
ParameterInfo[] parameterInfos = constructor.GetParameters();
Type[] parameters = new Type[parameterInfos.Length + 1];
parameters[0] = typeof(IActorDeactivationInterception);
for (int index = 1; index <= parameterInfos.Length; index++)
{
parameters[index] = parameterInfos[index - 1].ParameterType;
}
ConstructorBuilder constructorBuilder =
typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, parameters);
for (int argumentIndex = 0; argumentIndex < parameters.Length; argumentIndex++)
constructorBuilder.DefineParameter(
argumentIndex + 1,
ParameterAttributes.None,
$"arg{argumentIndex}");
ILGenerator generator = constructorBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
for (int index = 1; index < parameters.Length; index++)
{
generator.Emit(OpCodes.Ldarg, index + 1);
}
generator.Emit(OpCodes.Call, constructor);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, fldInterceptor);
generator.Emit(OpCodes.Ret);
}
}
/// <summary>
/// Builds a type in the dynamic assembly, if already the type is not created.
/// </summary>
/// <returns></returns>
public void InterceptAllMethods()
{
const MethodAttributes targetMethodAttributes =
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig;
var methodInfo = target.GetMethod("OnDeactivateAsync", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
{
if (methodInfo.IsVirtual)
{
Type[] paramTypes = GetParameterTypes(methodInfo.GetParameters());
MethodBuilder methodBuilder =
typeBuilder.DefineMethod(methodInfo.Name, targetMethodAttributes, methodInfo.ReturnType, paramTypes);
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, fldInterceptor);
ilGenerator.Emit(OpCodes.Call, typeof(IActorDeactivationInterception).GetMethod("Intercept"));
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Call, methodInfo);
ilGenerator.Emit(OpCodes.Ret);
return;
}
}
}
private Type[] GetParameterTypes(ParameterInfo[] parameterInfos)
{
Type[] parameters = new Type[parameterInfos.Length];
int index = 0;
foreach (var parameterInfo in parameterInfos)
{
parameters[index++] = parameterInfo.ParameterType;
}
return parameters;
}
private TypeBuilder typeBuilder;
private ModuleBuilder moduleBuilder;
private readonly Type target;
private FieldInfo fldInterceptor;
}
}
OnActorDeactivateInterceptor.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Actors
{
using Microsoft.Practices.Unity;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
public class OnActorDeactivateInterceptor : IActorDeactivationInterception
{
private readonly IUnityContainer container;
public OnActorDeactivateInterceptor(IUnityContainer container)
{
this.container = container;
}
public void Intercept()
{
this.container.Dispose();
}
}
}
UnityFabricExtensions.cs
namespace SInnovations.Azure.ServiceFabric.Unity
{
using System;
using System.Fabric;
using Microsoft.Practices.Unity;
using Microsoft.ServiceFabric.Actors;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
using SInnovations.Azure.ServiceFabric.Unity.Actors;
public static class UnityFabricExtensions
{
public static IUnityContainer WithFabricContainer(this IUnityContainer container)
{
return container.WithFabricContainer(c => FabricRuntime.Create());
}
public static IUnityContainer WithFabricContainer(this IUnityContainer container, Func<IUnityContainer,FabricRuntime> factory)
{
container.RegisterType<FabricRuntime>(new ContainerControlledLifetimeManager(), new InjectionFactory(factory));
return container;
}
public static IUnityContainer WithActor<TActor>(this IUnityContainer container) where TActor : ActorBase
{
if (!container.IsRegistered<IActorDeactivationInterception>())
{
container.RegisterType<IActorDeactivationInterception, OnActorDeactivateInterceptor>(new HierarchicalLifetimeManager());
}
container.RegisterType(typeof(TActor), ActorProxyTypeFactory.CreateType<TActor>(),new HierarchicalLifetimeManager());
container.Resolve<FabricRuntime>().RegisterActorFactory(() => {
try {
var actor = container.CreateChildContainer().Resolve<TActor>();
return actor;
}
catch (Exception ex)
{
throw;
}
});
return container;
}
public static IUnityContainer WithStatelessFactory<TFactory>(this IUnityContainer container, string serviceTypeName) where TFactory : IStatelessServiceFactory
{
if (!container.IsRegistered<TFactory>())
{
container.RegisterType<TFactory>(new ContainerControlledLifetimeManager());
}
container.Resolve<FabricRuntime>().RegisterStatelessServiceFactory(serviceTypeName, container.Resolve<TFactory>());
return container;
}
public static IUnityContainer WithStatefulFactory<TFactory>(this IUnityContainer container, string serviceTypeName) where TFactory : IStatefulServiceFactory
{
if (!container.IsRegistered<TFactory>())
{
container.RegisterType<TFactory>(new ContainerControlledLifetimeManager());
}
container.Resolve<FabricRuntime>().RegisterStatefulServiceFactory(serviceTypeName, container.Resolve<TFactory>());
return container;
}
public static IUnityContainer WithService<TService>(this IUnityContainer container, string serviceTypeName)
{
container.Resolve<FabricRuntime>().RegisterServiceType(serviceTypeName, typeof(TService));
return container;
}
}
}
如果您使用的是 Autofac,他们有专门的集成包:
https://alexmg.com/introducing-the-autofac-integration-for-service-fabric/ https://www.nuget.org/packages/Autofac.ServiceFabric/
简而言之,如您所料,使用 ActorRuntime.RegisterActorAsync
/ ServiceRuntime.RegisterServiceAsync
进行注册。然而,更有问题的部分,即对象释放,在 OnDeactivateAsync
/ OnCloseAsync
/ OnAbort
覆盖中使用动态代理自动处理。适当的生命周期范围也得到维护。
在撰写本文时,它仍处于 Alpha 阶段(上个月刚刚发布)。
@abatishchev 我认为你指的是 Service-Locator 反模式。依赖注入和 Service-Locator 都是控制反转的变体。