Autofac注册多个服务的多个装饰器

时间:2019-01-20 18:09:12

标签: c# autofac

我的应用程序中提供以下服务:

public interface IDecorableService
{

}

public interface IServiceDecorator
{

}

public interface ICommentService
{
   Task<Comment> AddAsync(Comment comment);
}

public class CommentService : ICommentService, IDecorableService
{
   public async Task<Comment> AddAsync(Comment comment)
   {
      //some code
   }
}

[DecorationOrder(Order = 1)]
public class EventLoggingCommentService : ICommentService, IServiceDecorator
{
   private readonly ICommentService _commentService;

   private readonly IEventLoggerService _eventLoggerService;

   public EventLoggingCommentService(ICommentService commentService, IEventLoggerService eventLoggerService)
   {
      _commentService = commentService;
      _eventLoggerService = eventLoggerService;
   }

   public async Task<Comment> Add(Comment comment)
   {
      comment = await _commentService.AddAsync(comment);
      //log comment added event by eventLogService
      return comment;
   }
}

[DecorationOrder(Order = 2)]
public class NotificationCommentService : ICommentService, IServiceDecorator
{
   private readonly ICommentService _commentService;

   private readonly INotificationService _notificationService;

   public NotificationCommentService(ICommentService commentService, INotificationService notificationService)
   {
      _commentService = commentService;
      _notificationService = notificationService;
   }

   public async Task<Comment> Add(Comment comment)
   {
      comment = await _commentService.AddAsync(comment);
      //send notifications about comment by notificationService
      return comment;
   }
}

我还有一些类似于CommentService的服务(例如PostService)和一些不需要修饰的服务。

我使用的是Autofac,我需要为每个需要装饰的服务(以指定的顺序)注册装饰器,并将其他服务注册为self。我不知道。有多少服务需要装饰。

我尝试执行以下操作:

public class BusinessLayerModule : Module
{
   private readonly object[] _tags;

   private readonly string[] _skippingInterfaces = new string[]
   {
      nameof(IDecorableService),
      nameof(IDecoratedService)
   };

   public BusinessLayerModule(List<object> tags)
   {
      _tags = tags?.ToArray();
   }

   protected override void Load(ContainerBuilder builder)
   {
      Assembly assembly = Assembly.GetExecutingAssembly();

      //Registering non-decorable services
      builder.RegisterAssemblyTypes(assembly)
                .Where(t => t.IsClass && !t.IsAbstract && t.Name.EndsWith("Service") && !t.GetInterfaces().Any(x => _skippingIntefaces.Contains(x.Name)))
                .AsSelf()
                .InstancePerMatchingLifetimeScope(_tags);

      //Registering decorable services
      RegisterDecorators(builder, assembly, _tags);
   }

   private void RegisterDecorators(ContainerBuilder builder, Assembly assembly, object[] tags)
   {
      //Getting all services which can be decorated
      List<Type> decorableServices = assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && t.Name.EndsWith("Service")
                                                                      && t.GetInterface(nameof(IDecorableService)) != null
                                                                      && t.GetInterface(nameof(IServiceDecorator)) == null).ToList();


        foreach (Type type in decorableServices)
        {
            //Getting the base interface, for example, ICommentService
            Type baseType = type.GetInterfaces().First(x => x.Name.EndsWith(type.Name));

            MethodInfo mi = this.GetType().GetMethod(nameof(RegisterDecoratedService), BindingFlags.NonPublic | BindingFlags.Instance);
            MethodInfo gmi = mi.MakeGenericMethod(baseType, type);
            gmi.Invoke(this, new object[] {builder, assembly, baseType, type, tags});
        }
    }

   private void RegisterDecoratedService<TInterface, TImplementation>(ContainerBuilder builder, Assembly assembly, Type baseType, Type implType, object[] tags)
    {
        //Getting all decorators of the service ordering by decoration order
        List<Type> decorators = assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && t.Name.EndsWith("Service")
                                                               && t.GetInterface(baseType.Name) != null
                                                               && t.GetInterface(nameof(IServiceDecorator)) != null)
            .OrderBy(t =>
            {
                DecorationOrderAttribute order = t.GetCustomAttribute<DecorationOrderAttribute>();
                return order?.Order ?? 0;
            }).ToList();
        if (!decorators.Any())
        {
            //If there are no decorators, just registering base service
            builder.RegisterType<TImplementation>()
                .As<TInterface>()
                .InstancePerMatchingLifetimeScope(tags);
        }
        else
        {
            builder.RegisterType<TImplementation>()
                .Named<TInterface>(implType.FullName)
                .InstancePerMatchingLifetimeScope(tags);

            MethodInfo mi = this.GetType().GetMethod(nameof(RegisterDecorator), BindingFlags.NonPublic | BindingFlags.Instance);

            //Registering decorators
            for (int i = 0; i &lt; decorators.Count; i++)
            {
                MethodInfo gmi = mi.MakeGenericMethod(baseType, decorators[i]);
                gmi.Invoke(this, new object[] {builder, (i == 0) ? implType : decorators[i - 1], decorators[i], tags, i != decorators.Count - 1 });
            }
        }

    private void RegisterDecorator<TInterface, TDecorator>(ContainerBuilder builder, Type baseType, Type decoratorType, object[] tags, bool hasKey)
    {
       string decoratorName = decoratorType.FullName;

       builder.RegisterType<TDecorator>()
                .Named<TInterface>(decoratorName)
                .InstancePerMatchingLifetimeScope(tags);
       builder.RegisterDecorator<TInterface>((c, inner) => c.ResolveNamed<TInterface>(decoratorName, TypedParameter.From(inner)), baseType.FullName, hasKey ? decoratorName : null)
                .InstancePerMatchingLifetimeScope(tags);
     }
}
}

当我进行API请求时,出现以下错误:
检测到循环组件依赖项:MyApp.WebUI.Api.RatingsController-> MyApp.Logic.Services.RatingService-> MyApp.Logic.Handlers.Ratings.RatingHandler []-> MyApp.Logic.Handlers.Ratings.CommentRatingHandler-> System.Object -> MyApp.Logic.Services.Decorated.WithEventLogging.CommentService-> System.Object。”。

我要实现以下目标
1.每个具有修饰服务的服务都需要注册为修饰器(例如,CommentService-> EventLoggingCommentService-> NotificationCommentService,PostService-> EventLoggingPostService-> NotificationPostService,...)
2.每个未修饰服务的服务都需要注册为自己(例如,FavoritesObjectService)。

能否请你告诉我我在做错什么。

1 个答案:

答案 0 :(得分:0)

最后,我找到了解决方案。我将RegisterDecoratedService更改如下:

private void RegisterDecorators(ContainerBuilder builder, Assembly assembly, object[] tags)
{
   List<Type> decorableServices = assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && t.Name.EndsWith("Service")
                                                                          && t.GetInterface(nameof(IDecorableService)) != null
                                                                          && t.GetInterface(nameof(IServiceDecorator)) == null).ToList();


   foreach (Type type in decorableServices)
   {
      Type baseType = type.GetInterfaces().FirstOrDefault(x => x.Name.EndsWith(type.Name));
      if (baseType == null)
      {
         builder.RegisterType(type)
                .AsSelf()
                .InstancePerMatchingLifetimeScope(tags);
         break;
      }

      MethodInfo mi = this.GetType().GetMethod(nameof(RegisterDecoratedService), BindingFlags.NonPublic | BindingFlags.Instance);
      MethodInfo gmi = mi.MakeGenericMethod(baseType, type);
      gmi.Invoke(this, new object[] {builder, assembly, tags});
   }
}



private void RegisterDecoratedService<TInterface, TImplementation>(ContainerBuilder builder, Assembly assembly, object[] tags)
   {
      List<Type> decorators = assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && t.Name.EndsWith("Service")
                                                                       && t.GetInterface(typeof(TInterface).Name) != null
                                                                       && t.GetInterface(nameof(IServiceDecorator)) != null)
                    .OrderBy(t =>
                    {
                        DecorationOrderAttribute order = t.GetCustomAttribute<DecorationOrderAttribute>();
                        return order?.Order ?? 0;
                    }).ToList();

      if (!decorators.Any())
      {
         builder.RegisterType<TImplementation>()
                .As<TInterface>()
                .InstancePerMatchingLifetimeScope(tags);
      }
      else
      {
         string implName = typeof(TImplementation).Name;

         builder.RegisterType<TImplementation>()
                .Named<TInterface>(implName)
                .InstancePerMatchingLifetimeScope(tags);

         for (int i = 0; i < decorators.Count; i++)
         {
            string decoratorKey = decorators[i].FullName;
            string fromKey = (i == 0) ? implName : $"{implName}Decorator{i}";
            string toKey = $"{implName}Decorator{i + 1}";

            builder.RegisterType(decorators[i])
                   .Named<TInterface>(decoratorKey)
                   .InstancePerMatchingLifetimeScope(tags);

            if (i != decorators.Count - 1)
            {
               builder.RegisterDecorator<TInterface>((c, inner) => c.ResolveNamed<TInterface>(decoratorKey, TypedParameter.From(inner)), fromKey, toKey)
                                .InstancePerMatchingLifetimeScope(tags);
             }
             else
             {
                 builder.RegisterDecorator<TInterface>((c, inner) => c.ResolveNamed<TInterface>(decoratorKey, TypedParameter.From(inner)), fromKey)
                                .InstancePerMatchingLifetimeScope(tags);
              }
           }
        }
     }

现在它可以用于2个和3个装饰器。

相关问题