可以为注释创建抽象吗?
Can one create abstractions for annotations?
我为调度作业创建了以下抽象:
public interface IJobData
{ }
public interface IJob<in TJobData> where TJobData : IJobData
{
Task ExecuteAsync(TJobData jobData);
}
我在应用层使用它来创造就业机会。例如
public record ForgotPasswordJobData() : IJobData;
public class ForgotPasswordJob : IJob<ForgotPasswordJobData>
{
public Task ExecuteAsync(ForgotPasswordJobData jobData)
{
// Do some work
return Task.CompletedTask;
}
}
现在我想用
装饰 ExecuteAsync 方法
[AutomaticRetry(Attempts = 5)]
但是我不想把它放在应用层,因为这会产生对基础设施层的依赖。 AutomaticRetry 是 hangfire 库的一个特性,它位于基础设施层。
有没有办法在应用层抽象[AutomaticRetry(Attempts = 5)]
?
如果您使用 Interface
该属性将不会继承到您的实现中。
但是如果你使用抽象class它会继承
public interface IJobData
{ }
public abstract class MyJob<TJobData> where TJobData : IJobData
{
[AutomaticRetry(Attempts = 5)]
public abstract Task ExecuteAsync(TJobData jobData);
}
这条评论让我走上正轨:
I would go for JobFilter with passive attribute. See
whosebug.com/a/57396553/1236044 In the
ServerFilterProvider.GetFilters method, you should "just" need to
search the job.Method.GetCustomAttributes for your own passive
MyAutomaticRetry attribute. Depending if you find one or not, you
would return a JobFilter holding a Hangfire.AutomaticRetryAttribute.
Sorry miss time to set up a correct answer
在应用层定义自定义属性:
[AttributeUsage(AttributeTargets.Method)]
public class JobRetryAttribute : Attribute
{
public int Attempts;
public bool DeleteOnAttemptsExceeded;
public JobRetryAttribute(int Attempts, bool DeleteOnAttemptsExceeded)
{
this.Attempts = Attempts;
this.DeleteOnAttemptsExceeded = DeleteOnAttemptsExceeded;
}
}
创建 hangfire 作业过滤器提供程序:
public class ServerFilterProvider : IJobFilterProvider
{
public IEnumerable<JobFilter> GetFilters(Job job)
{
var attribute = job.Method
.GetCustomAttributesData()
.Where(a => a.AttributeType == typeof(JobRetryAttribute))
.Select(a => new AutomaticRetryAttribute
{
Attempts = Convert.ToInt32(a.ConstructorArguments.First().Value),
OnAttemptsExceeded = Convert.ToBoolean(a.ConstructorArguments.Skip(1).First().Value) ? AttemptsExceededAction.Delete : AttemptsExceededAction.Fail
})
.First();
if (attribute != null)
{
return new JobFilter[] { new JobFilter(attribute, JobFilterScope.Method, null) };
}
return Enumerable.Empty<JobFilter>();
}
}
使用它:
JobFilterProviders.Providers.Add(new ServerFilterProvider());
我为调度作业创建了以下抽象:
public interface IJobData
{ }
public interface IJob<in TJobData> where TJobData : IJobData
{
Task ExecuteAsync(TJobData jobData);
}
我在应用层使用它来创造就业机会。例如
public record ForgotPasswordJobData() : IJobData;
public class ForgotPasswordJob : IJob<ForgotPasswordJobData>
{
public Task ExecuteAsync(ForgotPasswordJobData jobData)
{
// Do some work
return Task.CompletedTask;
}
}
现在我想用
装饰 ExecuteAsync 方法[AutomaticRetry(Attempts = 5)]
但是我不想把它放在应用层,因为这会产生对基础设施层的依赖。 AutomaticRetry 是 hangfire 库的一个特性,它位于基础设施层。
有没有办法在应用层抽象[AutomaticRetry(Attempts = 5)]
?
如果您使用 Interface
该属性将不会继承到您的实现中。
但是如果你使用抽象class它会继承
public interface IJobData
{ }
public abstract class MyJob<TJobData> where TJobData : IJobData
{
[AutomaticRetry(Attempts = 5)]
public abstract Task ExecuteAsync(TJobData jobData);
}
这条评论让我走上正轨:
I would go for JobFilter with passive attribute. See whosebug.com/a/57396553/1236044 In the ServerFilterProvider.GetFilters method, you should "just" need to search the job.Method.GetCustomAttributes for your own passive MyAutomaticRetry attribute. Depending if you find one or not, you would return a JobFilter holding a Hangfire.AutomaticRetryAttribute. Sorry miss time to set up a correct answer
在应用层定义自定义属性:
[AttributeUsage(AttributeTargets.Method)]
public class JobRetryAttribute : Attribute
{
public int Attempts;
public bool DeleteOnAttemptsExceeded;
public JobRetryAttribute(int Attempts, bool DeleteOnAttemptsExceeded)
{
this.Attempts = Attempts;
this.DeleteOnAttemptsExceeded = DeleteOnAttemptsExceeded;
}
}
创建 hangfire 作业过滤器提供程序:
public class ServerFilterProvider : IJobFilterProvider
{
public IEnumerable<JobFilter> GetFilters(Job job)
{
var attribute = job.Method
.GetCustomAttributesData()
.Where(a => a.AttributeType == typeof(JobRetryAttribute))
.Select(a => new AutomaticRetryAttribute
{
Attempts = Convert.ToInt32(a.ConstructorArguments.First().Value),
OnAttemptsExceeded = Convert.ToBoolean(a.ConstructorArguments.Skip(1).First().Value) ? AttemptsExceededAction.Delete : AttemptsExceededAction.Fail
})
.First();
if (attribute != null)
{
return new JobFilter[] { new JobFilter(attribute, JobFilterScope.Method, null) };
}
return Enumerable.Empty<JobFilter>();
}
}
使用它:
JobFilterProviders.Providers.Add(new ServerFilterProvider());