可以为注释创建抽象吗?

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());