簡體   English   中英

Autofac注冊多個服務的多個裝飾器

[英]Autofac register multiple decorators of multiple services

我的應用程序中提供以下服務:

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)。

你能告訴我我在做什么錯。

最后,我找到了解決方案。 我將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個裝飾器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM