использовать внедрение зависимостей в собственном хосте Signalr 2.0?

С помощью SignalR 2.0 в размещенном на собственном сервере приложении: эти инструкции у вас примерно так:

class Startup
{
   public void Configuration(IAppBuilder app)
   {
       app.MapSignalR(new HubConfiguration { Resolver = ... });
   }
}
class Program
{
    static void Main(string[] args)
    {
        using (WebApp.Start("http://localhost:8080")) // constructs Startup instance internally
        {
            Console.WriteLine("Server running on {0}", url);
            Console.ReadLine();
        }
    }
}

Вы заметите, что экземпляр класса Startup создается с помощью некоторой закулисной магии. Я не могу понять, как заполнить зависимости от него. Есть ли способ переопределить конструкцию класса Startup, чтобы я мог вводить в него зависимости?


person Brannon    schedule 27.01.2014    source источник


Ответы (2)


Вместо замены IAppActivator вы можете просто зарегистрировать аргументы конструктора Startup с помощью Katana ServiceProvider.

Активатор IAppActivator по умолчанию будет разрешать любые службы, соответствующие типам аргументов конструктора запуска. Единственным недостатком является то, что вы не можете использовать WebApp.Start, так как это не предоставляет ServiceProvider:

public class MyService : IMyService
{
    private readonly IMyOtherService _myOtherService;

    // Services will be recursively resolved by Katana's ServiceProvider
    public MyService(IMyOtherService myOtherService)
    {
        _myOtherService = myOtherService;
    }

    // Implementation
}

public class Startup
{
   private readonly IMyService _myService;

   // Startup must have exactly one constructor.
   public Startup(IMyService myService)
   {
       _myService = myService
   }

   public void Configuration(IAppBuilder app)
   {
       app.MapSignalR(new HubConfiguration { Resolver = ... });
   }
}

using System;
using Microsoft.Owin.Hosting;
using Microsoft.Owin.Hosting.Services;
using Microsoft.Owin.Hosting.Starter;

public class Program
{
    static void Main(string[] args)
    {
        var url = "http://localhost:8080";

        var services = (ServiceProvider)ServicesFactory.Create();
        var options = new StartOptions(url);

        services.Add<IMyOtherService, MyOtherService>();
        services.Add<IMyService, MyService>();

        var starter = services.GetService<IHostingStarter>();

        using (starter.Start(options)) // constructs Startup instance internally
        {
            Console.WriteLine("Server running on {0}", url);
            Console.ReadLine();
        }
    }
}

Я скопировал реализацию WebApp.Start по умолчанию в Program.Main, но вместо немедленного вызова IHostingStarter.Start я сначала добавляю пользовательские службы: http://katanaproject.codeplex.com/SourceControl/changeset/view/c726b87e90c05677a256ca1821bac481f402d6bd#src/Microsoft.Owin.Hosting/WebApp.cs < /а>

Существует множество других перегрузок для ServiceProvider.Add, если они вам нужны: http://msdn.microsoft.com/en-us/library/microsoft.owin.hosting.services.serviceprovider(v=vs.111).aspx

Это должно быть намного проще, чем замена IAppActivator Katana с помощью StartOptions.Settings, как я предлагаю в своем предыдущем ответе.

Однако я оставляю свой предыдущий ответ, поскольку он более подробно объясняет, как устроен класс Startup и как заменить реализации службы по умолчанию с помощью словаря настроек.

person halter73    schedule 28.01.2014
comment
Мне пришлось привести ServicesFactory.Create() к ServiceProvider, чтобы получить методы Add. Это было ожидаемо? - person Brannon; 29.01.2014
comment
Вы совершенно правы. Я обновил свой пример, чтобы преобразовать возвращаемое значение из ServicesFactory.Create() в ServiceProvider. Вы можете сказать, что это безопасно, посмотрев на реализацию Create: " rel="nofollow noreferrer">katanaproject.codeplex.com/SourceControl/changeset/view/ - person halter73; 29.01.2014
comment
Это очень сложно. Переместите содержимое класса Startup в лямбда-функцию следующим образом: WebApp.Start(baseAddress, app => { app.MapSignalR(new HubConfiguration { Resolver = ... }); }. Тогда вам не нужно вводить вещи в класс запуска, вы можете вводить их в класс, вызвавший WebApp.Start, и ссылаться на них через замыкание. - person Mark; 22.01.2015

Ознакомьтесь с информацией об внедрении зависимостей здесь: http://www.asp.net/signalr/overview/signalr-20/extensibility/dependency-injection

Должно быть все, что вам нужно знать :)

Надеюсь это поможет!

person N. Taylor Mullen    schedule 27.01.2014
comment
Я уже прочитал этот конкретный документ. Увы, это относится только к IIS, а не к самообслуживанию. Вы заметите, что метод, который они используют App.MapSignalR(config), не существует при самостоятельном размещении. - person Brannon; 27.01.2014
comment
Прочтите его еще раз... Посмотрите прямо над разделом IoC Containers. - person N. Taylor Mullen; 27.01.2014
comment
Прямо над разделом «Контейнеры IoC» обсуждается внедрение в классы концентратора. У меня нет проблем. Я хочу впрыснуть ступичный инжектор. - person Brannon; 27.01.2014
comment
@Brannon App.MapSignalR(config) абсолютно существует при самостоятельном размещении! Вы можете заменить SignalR IAssemblyLocator, IHubDescriptorProvider и/или IHubActivator, если хотите внедрить инжектор-концентратор. Я даю краткое объяснение целей этих трех интерфейсов здесь: #21126475" title="signalr с ioc Castle Windsor, время жизни для концентраторов"> stackoverflow.com/questions/21111436/ - person halter73; 28.01.2014
comment
@ halter73, не могли бы вы сказать мне, где в коде создается класс Startup? И я до сих пор не верю, что App == WebApp. - person Brannon; 28.01.2014