Re: Как передать в WCF веб-сервис ссылку на другой компонент его же приложения?
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 18.04.15 12:58
Оценка: 5 (2)
Добрый день

Обычно для сценария, который вы описали, используются IInstanceProvider
Примеры его использования совместно с DI/IoC контейнерами есть в сети в большом количестве.
Если вы используете как-то распространенный (например тот же Autfac), то наверняка уже есть готовая реализация.

Ну а если не используете, то вот, например, стартовая статья: как этим пользоваться WCF Extensibility – IInstanceProvider
Re: Как передать в WCF веб-сервис ссылку на другой компонент его же приложения?
От: fedor.reznik  
Дата: 18.04.15 17:46
Оценка: 2 (1)
Здравствуйте, IvanXXX, Вы писали:

IXX>Вопрос: как передать веб-сервису, автоматом создаваемому средой WCF при [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] или [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)], ссылку на какой-либо компонент этого же приложения (очередь запросов, процессор и т.п.).


Есть толковый пример с описанием для Unity:
http://www.devtrends.co.uk/blog/introducing-unity.wcf-providing-easy-ioc-integration-for-your-wcf-services
https://unitywcf.codeplex.com/

В принципе, допиливается под любой другой IoC контейнер. Главное вдумчиво прочитайте, ибо основное не напортачить со временем жизни объектов и disposables.
Как передать в WCF веб-сервис ссылку на другой компонент его же приложения?
От: IvanXXX  
Дата: 18.04.15 12:49
Оценка:
Доброго времени суток.

Прошу прощения за глупый вопрос — я новичок в WCF, а ответ найти не удается.

Итак, имеется WCF веб-сервис, который принимает запросы от клиентов и передает их на обработку процессорам (предназначенным для обработки запросов логическим компонентам сервера). Экземпляры веб-сервиса одного и того же класса могут "висеть" на разных адресах и передавать полученные запросы одного и того же типа разным процессорам.

Вопрос: как передать веб-сервису, автоматом создаваемому средой WCF при [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] или [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)], ссылку на какой-либо компонент этого же приложения (очередь запросов, процессор и т.п.).

За недостатком знаний наиболее очевидный вариант — использовать статическое поле — член класса веб-сервиса, в него записывать метод — селектор процессора для входящих запросов в зависимости от параметров клиента и веб-сервиса а-ля "void PostRequest(Request request, string clientUri, string serverUri)". Проблема в том, что приложение построено на интерфейсах (тестируемость, DI/IoC), а статические члены классов реализацией интерфейсов не являются.
Re[2]: Как передать в WCF веб-сервис ссылку на другой компон
От: IvanXXX  
Дата: 19.04.15 07:04
Оценка:
Здравствуйте, Михаил.

Относительно IInstanceProvider: проблема в том, что экземпляр провайдера создается средой WCF путем вызова конструктора без параметров. Если у меня была проблема — передать ссылки на какие-то объекты создаваемому веб-сервису, то теперь проблема — передать их провайдеру, который создает сервис.

Нашел решение попроще:
namespace Server.Impl
{
    class Program
    {
        static void Main(string[] args)
        {
            // Step 1 Create a URI to serve as the base address.
            var baseAddress = new Uri("http://localhost:8000/Server.Impl/");

            // Step 2 Create a ServiceHost instance
            var host = new MyServiceHost("Initialization data should be here", typeof(Service), baseAddress);

            try
            {
                // Step 3 Add a service endpoint.
                host.AddServiceEndpoint(typeof(IService), new WSHttpBinding(), "http://localhost:8000/Server.Impl/service/wshttpbinding");

                // Step 4 Enable metadata exchange.
                var smb = new ServiceMetadataBehavior {HttpGetEnabled = true};
                host.Description.Behaviors.Add(smb);

                // Step 5 Start the service.
                host.Open();
                Console.WriteLine("The service is ready.");
                Console.WriteLine("Press <ENTER> to terminate service.");
                Console.WriteLine();
                Console.ReadLine();

                // Close the ServiceHostBase to shutdown the service.
                host.Close();
            }
            catch (CommunicationException ce)
            {
                Console.WriteLine("An exception occurred: {0}", ce.Message);
                host.Abort();
            }
        }
    }

    public class MyServiceHost : ServiceHost
    {
        public object Data { get; private set; }

        public MyServiceHost(object data, Type serviceType, params Uri[] baseAddresses)
            :base(serviceType, baseAddresses)
        {
            Data = data;
        }
    }
}


Теперь из любого метода веб-сервиса можно обратиться к данным, переданным приложением:
var appData = ((MyServiceHost)OperationContext.Current.Host).Data;


Смущает только очевидная простота схемы по сравнению с расширением WCF через custom IInstanceProvider.
Отредактировано 19.04.2015 7:06 IvanXXX . Предыдущая версия . Еще …
Отредактировано 19.04.2015 7:05 IvanXXX . Предыдущая версия .
Отредактировано 19.04.2015 7:05 IvanXXX . Предыдущая версия .
Отредактировано 19.04.2015 7:04 IvanXXX . Предыдущая версия .
Re[3]: Как передать в WCF веб-сервис ссылку на другой компон
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 19.04.15 12:20
Оценка:
Здравствуйте, IvanXXX, Вы писали:

IXX>Относительно IInstanceProvider: проблема в том, что экземпляр провайдера создается средой WCF путем вызова конструктора без параметров. Если у меня была проблема — передать ссылки на какие-то объекты создаваемому веб-сервису, то теперь проблема — передать их провайдеру, который создает сервис.

Честно, не понял в чем проблема...
Если вы используете Self-Hosting схему, т.е. сами создаете ServiceHost, то что вам мешает сделать, например так:

Создать InstanceProvider с конструктором, в который вы будете передавать все нужные данные (можете сразу совместить его с IServiceBehavior) — реализация есть в статье, на которую я давал ссылку выше.
class InstanceProvider : IInstanceProvider, IServiceBehavior
{
    private readonly object _instanceData;

    public InstanceProvider(object instanceData)
    {
        _instanceData = instanceData;
    }

    // Реализация обоих интерфейсов опущена
}


А далее сделать как-то так:
object instanceData = new object();
var host = new ServiceHost(typeof (Service));
host.Description.Behaviors.Add(new InstanceProvider(instanceData));



Если у вас IIS хостинг, то просто код инициализации хоста переедет в фабрику хостов.

IXX>Теперь из любого метода веб-сервиса можно обратиться к данным, переданным приложением:

IXX>
IXX>var appData = ((MyServiceHost)OperationContext.Current.Host).Data;
IXX>

Ну и где вы избавились от неявных зависимостей? Вы же теперь классы привязали даже не к статическому полю, а к полю внутри инфраструктуры. Т.е. для тестирования ваших сервисов, вам теперь придется поднимать всю WCF инфраструктуру (я сильно сомневаюсь, что вы сможете легко создать или замокировать OperationContext и иже с ним.

IXX>Смущает только очевидная простота схемы по сравнению с расширением WCF через custom IInstanceProvider.

Ну так он и сильно хуже.
Помимо того, что вы не избавились от зависимости, а только её усилили (т.к. теперь вы зависите еще и от инфраструктуры WCF, через которою вы получаете все данные), вы также имеете только 1 экземпляр данных, которые можно передать сервису. Т.е. если тут будет какой-нибудь репозиторий, который нужно создавать и уничтожать на каждый запрос — вы этого сделать не сможете, у вас время жизни поля Data равно времени жизни хоста, а не экземпляра сервиса.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.