我的应用程序中提供以下服务:
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)。
能否请你告诉我我在做错什么。
答案 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个装饰器。