Внедрение зависимостей Ninject с веб-заданиями для DbContext в области статической функции

Есть ли способ подключиться к выполнению функции веб-заданий, чтобы мы могли иметь область действия для каждой функции? Что-то вроде этого:

kernel.Bind<MyDbContext>().ToSelf().InWebJobFunctionScope();

Я хотел бы использовать InScope() из Ninject, но я не знаю, где я могу найти что-то похожее на статическое HttpContext.Current, но для запущенного WebJob.


person jsgoupil    schedule 12.04.2016    source источник
comment
Привет, JS! Я открыл задачу github.com/Azure/azure. -webjobs-sdk-extensions/issues/39, но можете ли вы использовать InThreadScope?   -  person Thomas    schedule 13.04.2016
comment
@Thomas Я бы подумал, что область потока начнет вести себя неправильно при использовании шаблона async/await. Я попытался использовать BeginBlock для каждой статической функции, и все начало давать сбой. Итак, теперь я использую InNamedScope с CreateNameScope с пакетом nuget для сохранения контекста, чтобы наконец получить что-то, работающее для моего контекста БД... Определенно болезненно, и я сомневаюсь, что область имен должна работать так.   -  person jsgoupil    schedule 13.04.2016


Ответы (1)


Я знаю, что это старый, но у меня были такие же драмы. Начиная с более поздней версии веб-заданий, вы можете использовать экземпляры и методы экземпляров, а также передавать пользовательские экземпляры IJobActivator. Это удивительно легко.

Он отлично работает с Ninject. Я не видел ни одного примера Ninject, так что...

public class MyJobActivator : IJobActivator
{
    protected readonly IKernel _kernel;

    public MyJobActivator(IKernel kernel)
    {
        _kernel = kernel;
    }

    public T CreateInstance<T>()
    {
        return _kernel.Get<T>();
    }
}


public class MyBindings : NinjectModule
{
    public override void Load()
    {     
        Bind(typeof(DbContext)).To(typeof(MyEntities));
    }
}

class Program
{        
    static void Main()
    {
        using (IKernel kernel = new StandardKernel(new MyBindings()))
        {
            var jobHostConfiguration = new JobHostConfiguration
            {
                JobActivator = new MyJobActivator(kernel)
            };

            var host = new JobHost(jobHostConfiguration);

            // The following code will invoke a function called ManualTrigger and 
            // pass in data (value in this case) to the function
            host.Call(typeof(Reminders).GetMethod("ManualTrigger"), new { value = 20 });
        }
    }
}


public class Reminders
{
    private readonly IMyService _myService;

    public Reminders(IMyService myService)
    {
        _myService = myService;
    }

    // This function will be triggered based on the schedule you have set for this WebJob
    // This function will enqueue a message on an Azure Queue called queue
    [NoAutomaticTrigger]
    public async Task ManualTrigger(TextWriter log, int value, TextWriter logger)
    {
        try
        {   
            // process the notification request
            await _myService.FindAndSendReminders();
            await _myService.SaveChangesAsync();
        }
        catch (Exception e)
        {
            logger.WriteLine(e.Message);
            Console.WriteLine(e.Message);
            throw;
        }
    }
}

РЕДАКТИРОВАТЬ: В дополнение к вышесказанному я недавно узнал, что вам может не понадобиться использовать host.Call(typeof(Reminders).GetMethod("ManualTrigger"), по крайней мере, для непрерывных веб-заданий.

Вы просто делаете свой класс функций нестатическим и добавляете конструктор для инъекции, а затем делаете свой метод обработки нестатическим. Это показано ниже.

public class Program
{        
    static void Main()
    {
        using (IKernel kernel = new StandardKernel(new MyBindings()))
        {
            var jobHostConfiguration = new JobHostConfiguration
            {
                JobActivator = new MyJobActivator(kernel)
            };

            var host = new JobHost(jobHostConfiguration);

            // The following code ensures that the WebJob will be running continuously
            host.RunAndBlock();
        }
    }
}


public class Functions
{
    private readonly IMyService _myService;

    public Functions(IMyService myService)
    {
        _myService = myService;
    }        

    public async Task ProcessReminders([QueueTrigger("reminder-requests")] string notificationMessage, TextWriter logger)
    {
        try
        {   
            // process the notification request
            await _myService.FindAndSendReminders();
            await _myService.SaveChangesAsync();
        }
        catch (Exception e)
        {
            logger.WriteLine(e.Message);
            Console.WriteLine(e.Message);
            throw;
        }
    }
}

Я адаптировал исходный код из статьи, которую нашел для Autofac.

http://www.jerriepelser.com/blog/dedependency-injection-with-autofac-and-webjobs

Смотрите также

Внедрение зависимостей с помощью SDK Azure WebJobs?

И для непрерывных веб-заданий

http://www.ryansouthgate.com/2016/05/10/azure-webjobs-and-dependency-injection/

person Troyka    schedule 27.07.2016
comment
По некоторым причинам у меня были основания полагать, что это не работает с параллелизмом и/или не работает при вызове с трюком GetMethod(). @ Томас, как вы думаете, это охватывает то, что мы искали давным-давно: P? - person jsgoupil; 27.07.2016
comment
jsgoupil Я обновил свой ответ для непрерывных веб-заданий, которые не требуют использования метода get. Надеюсь, это поможет. - person Troyka; 03.08.2016
comment
@Troyka Что вы думаете о жизненном цикле объектов Entity Framework DbContext в запускаемых веб-заданиях? Очевидно, что процесс веб-задания постоянно активен, что говорит о том, что, возможно, мне следует ограничить DbContext одноэлементным, но, с другой стороны, функции задействованы для каждого сообщения, поэтому я мог ограничить DbContext для выполнения функции. Что ты посоветуешь? - person Howiecamp; 23.06.2017