es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Se puede crear abstracciones para las anotaciones?

He creado la siguiente abstracción para programar trabajos:

public interface IJobData
{ }

public interface IJob<in tjobdata=""> where TJobData : IJobData
{
    Task ExecuteAsync(TJobData jobData);
}

Utilizo esto en la capa de aplicación para crear trabajos. Por ejemplo:

public record ForgotPasswordJobData() : IJobData;

public class ForgotPasswordJob : IJob<forgotpasswordjobdata>
{
    public Task ExecuteAsync(ForgotPasswordJobData jobData)
    {
        // Realizar alguna tarea

        return Task.CompletedTask; 
    }
}

Ahora quiero decorar el método ExecuteAsync con:

[AutomaticRetry(Attempts = 5)]

Sin embargo, no quiero ponerlo en la capa de aplicación, porque esto creará una dependencia en la capa de infraestructura. AutomaticRetry es una funcionalidad de la biblioteca hangfire, que se encuentra en la capa de infraestructura.

¿Hay alguna manera de abstraer [AutomaticRetry(Attempts = 5)] en la capa de aplicación?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, hay una manera de abstraer [AutomaticRetry(Attempts = 5)] en la capa de la aplicación utilizando atributos personalizados en C#. Puede crear una clase de atributo personalizado en la capa de la aplicación y usarlo para decorar el método ExecuteAsync. Luego, puede crear una implementación de la interfaz IJob en la capa de infraestructura que lea el atributo personalizado y aplique el atributo [AutomaticRetry].

    Aquí tienes un ejemplo de implementación:

    // Atributo personalizado en la capa de la aplicación
    [AttributeUsage(AttributeTargets.Method)]
    public class RetryAttribute : Attribute
    {
        public int Attempts { get; set; }
    
        public RetryAttribute(int attempts)
        {
            Attempts = attempts;
        }
    }
    
    // Implementación de IJob en la capa de infraestructura
    public class RetryableJob<tjobdata> : IJob<tjobdata>
        where TJobData : IJobData
    {
        private readonly IJob<tjobdata> _innerJob;
    
        public RetryableJob(IJob<tjobdata> innerJob)
        {
            _innerJob = innerJob;
        }
    
        public async Task ExecuteAsync(TJobData jobData)
        {
            var retryAttribute = _innerJob.GetType().GetMethod(nameof(ExecuteAsync))
                .GetCustomAttribute<retryattribute>();
    
            if (retryAttribute != null)
            {
                var options = new BackgroundJobOptions {Attempts = retryAttribute.Attempts};
                await BackgroundJob.Enqueue(() => _innerJob.ExecuteAsync(jobData), options);
            }
            else
            {
                await _innerJob.ExecuteAsync(jobData);
            }
        }
    }
    

    Con esta implementación, puedes crear una clase envolvente RetryableJob alrededor de cualquier implementación de IJob y se aplicará el comportamiento [AutomaticRetry] basado en el atributo [Retry] en la capa de la aplicación:

    // Decora el método ExecuteAsync con [Retry] en la capa de la aplicación
    public class ForgotPasswordJob : IJob<forgotpasswordjobdata>
    {
        [Retry(Attempts = 5)]
        public Task ExecuteAsync(ForgotPasswordJobData jobData)
        {
            // Realiza algún trabajo
            return Task.CompletedTask; 
        }
    }
    
    // Envuelve ForgotPasswordJob en un RetryableJob en la capa de infraestructura
    var retryableJob = new RetryableJob<forgotpasswordjobdata>(new ForgotPasswordJob());
    

    De esta manera, la capa de la aplicación no tiene una dependencia directa en la biblioteca hangfire ya que la lógica [AutomaticRetry] se abstrae utilizando atributos personalizados.

Comments are closed.