2017-01-05 6 views
0

У меня есть несколько заданий пакетного задания для запуска, и мне было предложено иметь один webJob для запуска всей задачи, которые мне нужно планировать для запуска в разное время.Azure WebJobs - многократная фоновая задача в одиночных ошибках WebJob и Ef Была сделана попытка использовать контекст во время его настройки

Я использовал функцию таймера из webJob.Extensions.

т.е. в Program.cs

var config = new JobHostConfiguration 
      { 
       JobActivator = new AutofacActivator(ContainerConfig<Functions>.GetContainer()) 
      }; 

      if (config.IsDevelopment) 
      { 
       config.UseDevelopmentSettings(); 
      } 
      config.UseTimers(); 

      var host = new JobHost(config); 
      host.RunAndBlock(); 

и функция будет иметь несколько метод и срабатывают в интервале 30 мин.

public void ProcessMethod1([TimerTrigger("0 0/30 * * * *")] TimerInfo timer) 
{ 
    //Logic 
} 

public void ProcessMethod2([TimerTrigger("0 0/30 * * * *")] TimerInfo timer) 
{ 
    //Logic 
} 

Выпуск: Поскольку я использую Autofac DI. Я создаю экземпляр для DbContext в начале задания

JobActivator = new AutofacActivator(ContainerConfig<Functions>.GetContainer())

При выполнении webJob я получаю ошибки при выполнении DB выбрать как «была сделана попытка использовать контекст во время его сконфигурировано».

Так как я дал scope как InstancePerLifetimeScope(). Я хочу знать, получит ли операция Two тот же самый экземпляр?

Также для ведения журнала у меня есть аналогичная проблема, так как похоже, что для этих двух разных операций создается только один экземпляр.

Все, что я хочу, это отдельный экземпляр для DBCOntext и Logger на основе операции. Pls советует мне, как я могу установить DI для этого сценария.

Update:

public class AutofacActivator: IJobActivator 
    { 
     private readonly Autofac.IContainer _container; 

     public AutofacActivator(Autofac.IContainer container) 
     { 
      _container = container; 
     } 

     public T CreateInstance<T>() 
     { 
      return _container.Resolve<T>(); 
     } 
    } 

internal class WebJobIocModule<T> : Autofac.Module 
    { 
     protected override void Load(ContainerBuilder builder) 
     { 
      if (builder == null) 
       throw new ArgumentNullException("WebJobBuilder"); 


      //Cascade 
      builder.RegisterModule(new BusinessObjectIocModule()); 

      // Register the functions class - WebJobs will discover our triggers this way 
      builder.RegisterType<T>(); 
     } 
    } 



    public class BusinessObjectIocModule :Autofac.Module 
    { 
     protected override void Load(ContainerBuilder builder) 
     { 
      if(builder == null) throw new ArgumentNullException("BusinessObjectBuilder"); 


      //Cascade 
      builder.RegisterModule(new DataAccessRepoIocModule()); 

      builder.RegisterType<BusinessObjBpc>().AsImplementedInterfaces(); 

     } 
    } 

В DataAccessIOC:

string connectionString = ConfigurationManager.ConnectionStrings["DBConnectionAppKeyName"].ConnectionString; 
      optionsStagingBuilder.UseSqlServer(connectionString); 

      builder.RegisterType<DataAccessDbContext>() 
       .AsSelf() 
       .WithParameter("options", optionsStagingBuilder.Options) 
       .InstancePerLifetimeScope(); 
+0

вы можете разместить код AutofacActivator, код, который показывает, как вы зарегистрировали зависимости, а также коды класса, который инкапсулирует свои рабочие функции. Спасибо – Thomas

+0

Чтобы проверить, используете ли вы один и тот же экземпляр 'DbContext' в разных местах, вы можете пометить свой экземпляр DbContext уникальным значением и зарегистрировать его/проверить его при отладке. Добавьте свойство в свой 'DbContext' и заполните его новым Guid в конструкторе или что-то подобное. [Как упоминалось здесь] (https://github.com/aspnet/EntityFramework/issues/6488) – Diana

+0

@Thomas Спасибо .. Я рад найти код контейнера – RajGan

ответ

0

Если вы используете LifetimeScope для DbContext вы должны убедиться, что вы делаете новую область в каждом выполнении методов обработки, с помощью используя такой код:

public void ProcessMethod1([TimerTrigger("0 0/30 * * * *")] TimerInfo timer) 
{ 
    using (var scope = container.BeginLifetimeScope()) 
    { 
     //Logic 
    } 
} 

Это будет работать , но я думаю, что это может иметь побочные эффекты. Кроме того, для других компонентов более эффективно не создавать их при каждом выполнении методов обработки. Возможно, вы хотели бы использовать другую область.

Update - Как придать контейнер в функции конструктора:

В конструкторе вы можете использовать параметр Func<IContainer> вместо IContainer. Он будет работать как контейнерный завод.

Когда вы строите свой контейнер (в начале работы, в том месте, где вы строите свой контейнер) зарегистрировать экземпляр вашего контейнера завода:

Func<IContainer> containerFactory =() => yourContainer; 
... 
builder.RegisterInstance(containerFactory); 

Затем в конструкторе пусть Autofac впрыснуть завод и хранить контейнер в собственности:

public SomeConstructor(Func<IContainer> containerFactory, ...<other injected params>) 
{ 
    ... 
    this.container = containerFactory(); 
} 
+0

Я не смог получить экземпляр для контейнера. Это ошибка при попытке разрешить экземпляр FUnction. Ошибка: ни один из конструкторов, найденных с помощью «Autofac.Core.Activators.Reflection.DefaultConstructorFinder» в типе «Функции», может быть вызван доступными службами и параметрами: Не удается разрешить параметр «контейнер Autofac.IContainer» конструктора «Void .ctor (IbusinessOpsBpc, ILogging, Autofac.IContainer). – RajGan

+0

Я обновил свой ответ, чтобы показать способ ввода контейнера в конструктор, пожалуйста, посмотрите. Кроме того, [этот ответ] (http://stackoverflow.com/a/4609510/1182515) показывает другой подход. – Diana

+0

Спасибо за ваш ответ. Я пришел с аналогичным решением, которое скоро обновит образец кода .. – RajGan