Azure服务结构actordependency injection

有没有办法将依赖项注入Azure Service Fabric Actor的构造函数?

稍微使用dotPeek在这个区域进行了一些挖掘(尝试从每次调用的Autofac生命周期范围中解析actor),我认为诀窍是创建自己的StatelessActorServiceFactory实现,以及您自己的扩展方法用它注册演员。 虽然工厂类被标记为内部,但它的接口(IStatelessServiceFactory)和它创建的服务类型(StatelessActorServiceInstance)都是公共的。 不幸的是,它看起来并不像StatelessActorServiceInstance被设计为可扩展的(我希望这只是一个疏忽)。

不幸的是,看起来WcfActorCommunicationProvider也被标记为内部,因此您几乎必须从头开始创建自己的管道:

  1. 实现自己的IStatelessServiceFactory
  2. 实现自己的IStatelessServiceInstance,IActorService
  3. 实现自己的IActorCommunicationProvider
  4. 实现自己的IActorHost

看起来真的不值得付出努力,是吗? : – /

这就是我现在放弃的地方。 考虑到公共API的相对不成熟,我认为现在不值得尝试自己动手,因为如果这种function完全出现,他们可能会以一种破坏的方式这样做你自己实现的任何事情

更新

它现在全部在github和myget上: https : //github.com/s-innovations/S-Innovations.ServiceFabric.Unity

并且与aspnet核心dependency injection集成,没有太多麻烦,请查看readme.md的示例


我是Unity的长期用户,并决定制作所需的核心扩展方法,以便在与actor合作时获得良好的dependency injection体验。

我的program.cs现在看起来像这样:

internal static class Program { ///  /// This is the entry point of the service host process. ///  private static void Main() { try { using (var container = new UnityContainer()) { container.RegisterType(new HierarchicalLifetimeManager()); container.RegisterType(new HierarchicalLifetimeManager()); container.WithFabricContainer(); container.WithActor(); container.WithActor(); container.WithStatelessFactory("ManagementApiServiceType"); container.WithActor(); 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; } } } 

我在actor和服务中的位置可以放在构造函数中的依赖项中。

 public class VmssManagerActor : StatefulActor, IVmssManagerActor, IRemindable { public const string CheckProvision = "CheckProvision"; ///  /// Cluster Configuration Store ///  protected IMessageClusterConfigurationStore ClusterConfigStore { get; private set; } public VmssManagerActor(IMessageClusterConfigurationStore clusterProvider) { ClusterConfigStore = clusterProvider; } 

如果你觉得这很有用,并希望我把它放入一个nuget包中,那么请回答这个问题。

关于实施的一个注意事项,每个演员都会得到自己的范围。 这意味着使用实现IDisposable ‘HierarchicalLifetimeManager’注册的所有依赖项将自动放置在actor OnDeactivationAsync 。 这是通过使用动态类型动态地代理actor类来完成的,该动态类型拦截对OnDeactivationAsync的调用。 为此,Actor必须是公共定义的。

IActorDeactivationInterception.cs

 namespace SInnovations.Azure.ServiceFabric.Unity.Abstraction { ///  /// The  interface for defining an OnDeactivateInterception ///  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 { ///  /// Creates a new instance of the  class. ///  ///  public ActorProxyTypeFactory(Type target) { this.target = target; } ///  /// Creates the proxy registered with specific interceptor. ///  ///  public static T Create(IActorDeactivationInterception deactivation, params object[] args) { return (T)new ActorProxyTypeFactory(typeof(T)).Create(new object[] { deactivation }.Concat(args).ToArray()); } public static Type CreateType() { return new ActorProxyTypeFactory(typeof(T)).CreateType(); } ///  /// Creates the proxy registered with specific interceptor. ///  ///  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); } ///  /// Builds a dynamic assembly with  mode. ///  ///  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); } } ///  /// Builds a type in the dynamic assembly, if already the type is not created. ///  ///  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 factory) { container.RegisterType(new ContainerControlledLifetimeManager(), new InjectionFactory(factory)); return container; } public static IUnityContainer WithActor(this IUnityContainer container) where TActor : ActorBase { if (!container.IsRegistered()) { container.RegisterType(new HierarchicalLifetimeManager()); } container.RegisterType(typeof(TActor), ActorProxyTypeFactory.CreateType(),new HierarchicalLifetimeManager()); container.Resolve().RegisterActorFactory(() => { try { var actor = container.CreateChildContainer().Resolve(); return actor; } catch (Exception ex) { throw; } }); return container; } public static IUnityContainer WithStatelessFactory(this IUnityContainer container, string serviceTypeName) where TFactory : IStatelessServiceFactory { if (!container.IsRegistered()) { container.RegisterType(new ContainerControlledLifetimeManager()); } container.Resolve().RegisterStatelessServiceFactory(serviceTypeName, container.Resolve()); return container; } public static IUnityContainer WithStatefulFactory(this IUnityContainer container, string serviceTypeName) where TFactory : IStatefulServiceFactory { if (!container.IsRegistered()) { container.RegisterType(new ContainerControlledLifetimeManager()); } container.Resolve().RegisterStatefulServiceFactory(serviceTypeName, container.Resolve()); return container; } public static IUnityContainer WithService(this IUnityContainer container, string serviceTypeName) { container.Resolve().RegisterServiceType(serviceTypeName, typeof(TService)); return container; } } } 

我知道这已经过时了但是出于文档的考虑,DI现在可以像你期望的那样在Reliable Actor框架中得到支持。

 public class ActorOne : Actor, IMyActor{ private readonly IDependency _dependency; public ActorOne(IDependency dependency) { _dependency = dependency; }} 

然后使用Service Fabric注册Actor及其依赖关系,如下所示:

 using (FabricRuntime fRuntime = FabricRuntime.Create()){ fRuntime.RegisterActor(() => new ActorOne(new MyDependency()); Thread.Sleep(Timeout.Infinite);} 

为什么不在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(); } public async Task DoWorkAsync() { // Working with a RootElement with all dependencies are injected.. return await Task.FromResult(_rootElement.WorkingWithInjectedStuff()); } } 

如果你正在使用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中(上个月刚刚发布)。