2017-02-13 5 views
2

я имел ряд классов, которые я использовал для обработки WebJobs, которые выглядели примерно так:WebJob Dependency Injection Связывание с Generic класса

public class EnvelopeSalutationJob : BatchJob 
{ 
    public EnvelopeSalutationJob(StringWriter swLogger) 
     : base(swLogger, "Envelope Salutation Job") 
    { 
    } 

    [ Singleton() ] 
    public async Task ProcessMessage(
     [ QueueTrigger("%" + nameof(ContainerQueueConstants.EnvelopeSalutation) + "%") ] EnvelopeSalutationMessage msg, 
     TextWriter azureLogWriter 
    ) 
    { 
     PhaseNames.SetNames("Processing Homes", "Job Completed"); 

     await ExecuteFromMessage(msg, azureLogWriter, Launch); 
    } 
} 

Они хорошо работали, используя AutoFac в качестве основы DI, с конфигурацией, которая выглядела как это:

public static class ContainerConfig 
{ 
    public static IContainer GetContainer() 
    { 
     var builder = new ContainerBuilder(); 

     // per job 
     builder.RegisterType<StringWriter>(); 

     // jobs 
     builder.RegisterType<EnvelopeSalutationJob>(); 

     return builder.Build(); 
    } 
} 

Но в последнее время я хотел «genericize» рабочие места, чтобы они не были привязаны к конкретным DbContexts. Я пытался использовать шаблон, как это:

public class EnvelopeSalutationJob<TContext, TUser> 
    : BatchJob<TContext, TUser> 
    where TContext : IdentityDbContext<TUser>, ICampaignContext, new() 
    where TUser : IdentityUser, INamedUser 
{ 
    public EnvelopeSalutationJob(StringWriter swLogger) 
     : base(swLogger, "Envelope Salutation Job") 
    { 
    } 
    [ Singleton() ] 
    public async Task ProcessMessage(
     [ QueueTrigger("%" + nameof(ContainerQueueConstants.EnvelopeSalutation) + "%") ] EnvelopeSalutationMessage msg, 
     TextWriter azureLogWriter 
    ) 
    { 
     PhaseNames.SetNames("Processing Homes", "Job Completed"); 

     await ExecuteFromMessage(msg, azureLogWriter, Launch); 
    } 
} 

Конфигурация AutoFac изменяется на:

public static class ContainerConfig 
{ 
    public static IContainer GetContainer() 
    { 
     var builder = new ContainerBuilder(); 

     // per job 
     builder.RegisterType<StringWriter>(); 

     // jobs 
     builder.RegisterType<EnvelopeSalutationJob<ConnellJobContext, ConnellUser>>(); 

     return builder.Build(); 
    } 
} 

К сожалению, это не работает. Приложение консоли WebJobs запускается нормально, но оно жалуется:

Не найдено должностей. Попробуйте сделать свои классы и методы работы общественностью.

Невозможно ли привязать задания к экземплярам родовых классов?

ответ

2

По вашему описанию, я испытал этот вопрос на моей стороне, и я мог бы воспроизвести эту проблему следующим образом:

После того как я проверил Azure WebJobs SDK исходный код на мерзавца, я обнаружил, что DefaultTypeLocator.cs будет использовать IsJobClass, что применение Type.ContainsGenericParameters для фильтрации типов следующим образом:

public static bool IsJobClass(Type type) 
{ 
    if (type == null) 
    { 
     return false; 
    } 

    return type.IsClass 
     // For C# static keyword classes, IsAbstract and IsSealed both return true. Include C# static keyword 
     // classes but not C# abstract keyword classes. 
     && (!type.IsAbstract || type.IsSealed) 
     // We only consider public top-level classes as job classes. IsPublic returns false for nested classes, 
     // regardless of visibility modifiers. 
     && type.IsPublic 
     && !type.ContainsGenericParameters; 
} 

Кроме того, FunctionIndexer.cs будет использовать IsJobMethod фильтровать методы следующим образом:

public bool IsJobMethod(MethodInfo method) 
{ 
    if (method.ContainsGenericParameters) 
    { 
     return false; 
    } 

    if (method.GetCustomAttributesData().Any(HasJobAttribute)) 
    { 
     return true; 
    } 

    if (method.GetParameters().Length == 0) 
    { 
     return false; 
    } 

    if (method.GetParameters().Any(p => p.GetCustomAttributesData().Any(HasJobAttribute))) 
    { 
     return true; 
    } 

    return false; 
} 

Основываясь на моем понимании, Azure WebJobs SDK не поддерживает привязку заданий к экземплярам родовых классов в настоящее время. Вы можете определить свой BaseDbContext и использовать зависимость Injection от конструктора для инициализации своего экземпляра DbContext. Также вы можете добавить свой отзыв here.

 Смежные вопросы

  • Нет связанных вопросов^_^