[英]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 < 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.