Страницы

Поиск по вопросам

Показаны сообщения с ярлыком wcf. Показать все сообщения
Показаны сообщения с ярлыком wcf. Показать все сообщения

суббота, 11 апреля 2020 г.

Подобрать инструментальные средства - WPF and WCF

#c_sharp #net #wpf #entity_framework #wcf

                    
Добрый день! В WPF и многих других моментах к сожалению не очень силен, поэтому прошу
вашей помощи.

Пишу клиент-серверное ПО для небольшой авиакомпании. Пока что основное назначение
программы это учет самолетов, полетов, компонентов к ним, технического обслуживания
и т.д. База юзается Postgree, сейчас порядка 20 таблиц, дальше будет больше, из них
70% должны редактироваться пользователем. Используется связка Entity Framework Code
First + Npgsql

Взялся за этот проект причине желания научиться новому, т.к. с проектами подобного
рода еще не работал.

Сервер будет находиться на отдельной машине в локальной сети, количество одновременно
работающих клиентов будет около 10. Клиенты будут на WPF. В будущем возможно программа
выйдет за рамки локальной сети. Версия .NET Framework 4.5

В связи с этим несколько вопросов:

1) Какие полезные контролы, библиотеки можете посоветовать для интерфейса? В моей
голове все еще свежи воспоминания полуторагодовалой давности когда я нудно пилил курсовую
на WPF + DataGrid, в то время как некоторые однокурсники заюзали LightSwitch затратив
меньшие усилия и получив более приятный глазу результат. Но LightSwitch платный, поэтому
для моих целей он слабо подходит.

2) Как реализовать клиент-серверное взаимодействие? С сокетами хорошо знаком, и написать
на них не проблема. Но еще слышал про существование некоего WCF, может стоит попробовать его?

Вообще задача на мой взгляд более типична для 1С, о чем я честно сообщил заказчику,
но он сказал что не хочет с ним связываться.
    


Ответы

Ответ 1



Последнее время использую Elysium Extra- неплохо проработанные, бесплатные Win8-style компоненты с открытым исходным кодом. В основном заточены под MVVM. Установка: PM> Install-Package Elysium.Extra или искать Elysium Extra в NuGet

Ответ 2



Разумеется, лучше использовать WCF, чем писать все на сокетах. Даже если вы умеете работать с сокетами и не знаете WCF. Если у вас в проекте будет хотя бы 10 разных типов запросов между клиентом и сервером - то вы быстрее изучите WCF, чем успеете написать их все на сокетах.

Ответ 3



А не будет ли в данной ситуации, более адекватным использование ASP, а не связки WPF + WCF? Посмотрите и в эту сторону...

Ответ 4



Но LightSwitch платный, поэтому для моих целей он слабо подходит. Ну так купите его, если он устраивает полностью. Либо посмотрите в сторону бесплатных библиотек. Желательно, чтобы она была одна. Я предлагал заказчику ASP, но ему нужно десктопное приложение FireFox/Chrome/IE - вполне себе десктопные приложения. Заказчику требуется, чтобы его бизнес-цели выполнялись, а не десктопное приложение. Подозреваю, вы думаете несколько о другом, нежели о проблемах заказчика. Если не изменить свою точку зрения, этот "проект" скорее всего окажется бессмысленно потраченным временем. Но еще слышал про существование некоего WCF Я бы посмотрел в сторону ASP.NET Web Api, но опять же, многое зависит от того, что именно вы хотите делать. Нужен ли поллинг, броадкастинг. Все инструменты решают какие-то проблемы, нет правильного ответа на вопрос: "Что мне взять, чтобы заколотить клиент-серверное приложение", ответы на вопросы (а точнее сами вопросы) появляются только после уточнения требований по функционалу, быстродействию, UX и т.п. вещей.

Ответ 5



Но LightSwitch платный, поэтому для моих целей он слабо подходит How To Get Visual Studio LightSwitch For Free (Легально!) Однако замечу, что имел с этим инструментом много боли, так как допиливание снабжено кучей ограничений, накладываемых WPF и MVVM. Если проект небольшой - то да, решение вполне оправданное. Иначе стоит всё хорошо взвесить.

воскресенье, 15 марта 2020 г.

Реализация клиент-серверного приложения

#c_sharp #aspnet #сокет #wcf #клиент_сервер


Имеется следующая архитектура: клиентская часть(dll-ка на C#) отсылает определенное
количество картинок на сервер(либо Windows Service, либо Web Service), где они обрабатываются,
а потом отсылается ответ в виде XML файла результатов обработки.

Клиент - это просто автоматизированное приложение, без интерфейса и ввода вывода. 

Сервер. На нем крутится движок, использующий многопоточность (с помощью ThreadPool)
для обработки картинок.
Соответственно, когда обращается новый клиент, сервер создает новый поток, в котором
происходит обработка, по окончанию он отсылает ответ пользователю(xml-файл).
Нагрузка на сервер планируется не очень большая 3-20 одновременных подключений.

Пока что я не могу понять какая архитектура взаимодействия лучше всего подойдет для
моего случая. Есть несколько путей реализации, либо писать асинхронный сервер на сокетах,
либо использовать WCF, или просто написать ASP.NET приложение и залить его на IIS(к
этому варианту я склоняюсь больше всего).

Какой протокол передачи лучше всего использовать? Хватит ли HTTP для передачи большого
количества картинок(тогда можно двигаться в направлении Web Service), или стоит задуматься
о TCP/IP(здесь уже WCF)?

Кому интересно, несколько статей по созданию клиент-серверного приложения:

Example with ASYNC/AWAIT

Example with THREADS

Example with SOCKETS
    


Ответы

Ответ 1



HTTP, WCF и голый TCP справляются с заливкой картинок примерно одинаково. Особенно если учесть, что HTTP работает поверх TCP, а WCF - или поверх HTTP, или с собственным протоколом поверх TCP, в зависимости от настроек биндинга. Никакой ощутимой разницы между реализациями с точки зрения производительности не будет. То же самое с типом хостинга - между Self-Hosted и IIS нет практически никакой разницы (не при вашей нагрузке). Вам стоит использовать то, что вам удобнее в написании и поддержке.

воскресенье, 8 марта 2020 г.

WCF служба, wsDualHttpBinding и 80 порт

#c_sharp #net #http #wcf


При подключении к WCF службе вылетает exception, хотя в app.config конфиг явно указан
не 80 порт:


  An unhandled exception of type 'System.ServiceModel.AddressAlreadyInUseException'
occurred in
  System.ServiceModel.dll
  
  Additional information: HTTP could not register URL
  http://+:80/Temporary_Listen_Addresses/c3e45f68-abf2-4847-95a6-cfd3f512fc54/
  because TCP port 80 is being used by another application.


Самое странное, что на одном ПК вылетает exception, а на другом нет. В чем может
быть проблема?

app.config клиента :



     
        
    
    
        
            
                
            
        
        
            
            
        
    



app.config сервер:


  
    
  
  
    
      
        
        
        
          
            
          
        
      
    
    
      
        
          
        
      
    
  


    


Ответы

Ответ 1



Вы используете wsDualHttpBinding. В этом режиме клиент прослушивает некоторый адрес, где ожидает ответы от сервера. И вот этот-то адрес, который в конфиге вы не задавали, и находится на 80м порту по умолчанию! Используйте атрибут clientBaseAddress для указания обратного адреса на клиенте: Либо используйте другие способы соединения. Так, netTcpBinding - и без обратного адреса умеет передавать сообщения в обе стороны. Еще где-то в WCF есть поддержка веб-сокетов, но я не помню где. Теперь почему может быть занят 80й порт на некоторых компьютерах. Скорее всего, это Skype, который использует этот порт по умолчанию: Но, конечно же, не следует отбрасывать и вариант обычного веб-сервера, Apache, Nginx или Tomcat. А вот IIS с WCF "дружат", поскольку используют один и тот же HTTP.SYS.

WCF - назначение UriTemplate?

#c_sharp #wcf


Добрый день.

Я здесь с вопросом, который никак самостоятельно не могу осознать.


  Вопрос: что такое UriTemplate и с чем его едят?


Я разбирал на конкретных примерах. Например:

[ServiceContract(Namespace = "urn:example:services")]
    public interface ISomeWcf
    {
        [WebInvoke(Method = "GET",
            ResponseFormat = WebMessageFormat.Xml,
            BodyStyle = WebMessageBodyStyle.Wrapped,
            UriTemplate = "GetResult?client={client}&password={password}&messageId={messageId}")]
        string GetResultHttpGet(string client, string password, string messageId);

     }


В данном конкретном случае UriTemplate задает шаблон, по которому мы через REST-запрос
можем обратиться к методу GetResultHttpGet. Читал МСДН, но не разобрался.


  Зачем указывать Namespace = "urn:example:services" ?


Можете подсказать, что с UriTemplate делать? Такое впечатление что рядом брожу с
ответом, а сформулировать его не могу.

Спасибо
    


Ответы

Ответ 1



UriTemplate задаёт шаблон, по которому определяется, должен ли входящий запрос с данным Uri быть направлен на обслуживание методом GetResultHttpGet, а также сопоставляет части Uri параметрам метода. Допустим для данного контракта базовый адрес http://hostname/SomeWcf/ Если приложением (или прямо браузером) сделать GET запрос http://hostname/SomeWcf/GetResult?client=CLI&password=PWD&messageId=MSG то будет вызван метод GetResultHttpGet сервиса. При этом части Uri станут значениями соответствующих параметров: string GetResultHttpGet(string client, string password, string messageId) { //здесь части Uri станут значениями параметров: //client = "CLI"; //password = "PWD"; //messageId = "MSG"; ... } Если отклониться от шаблона, задав что-то другое, например http://hostname/SomeWcf/GetResult2?name=NAME или http://hostname/SomeWcf/GetResult3/Name/Foo то метод GetResultHttpGet вызван не будет. Что касается свойства Namespace у атрибута ServiceContract [ServiceContract(Namespace = "my.company.com")] то оно фигурирует в заголовке soap-envelope ... my.company.com/ISomeWcf/GetResultHttpGet ... ... Если его не указывать [ServiceContract] то вместо my.company.com там будет значение по умолчанию (http://tempuri.org). Если интерфейс, описывающий контракт находится в сборке, на которую ссылаются и клиент и сервер, то в принципе Namespace может быть любым. Если же интерфейс описан дважды - в клиентской части и в серверной, или если вы создаёте клиента для уже существующего сервиса с определённым Namespace, то Namespace должны совпадать, чтобы клиент и сервер понимали друг-друга, иначе будет ответ ... ... The message could not be processed because the action 'http://tempuri.org/ISomeWcf/GetResultHttpGet' is invalid or unrecognized.

Конфигурирование WCF-сервиса для передачи файлов, как и где это сделать?

#c_sharp #wcf #config #configuration


Пришлось впервые столкнуться с WCF, ибо есть задача - посредством WCF-службы отдавать
клиенту файлы по запросу клиента.

Предварительно была изучена теория, и выяснено, что файлы можно передавать:


Как есть, без предварительной настройки, разве что, выставив
maxMessageLengthи executionTimeoutInSeconds в довольно большие
значения.
Включить MTOM в качестве кодировщика.
Включить стриминг (потоковую передачу данных).


Точный размер передаваемых файлов я не знаю, но зато могу сказать, что на текущем
этапе вряд ли будут передаваться большущие файлы типа дампов БД или потокового видео. 
Но всё же, в стандартном подходе меня смущает то, что будет постоянная сериализация-десереализация
файлов в XML, а зачем лишние телодвижения?

Включение стриминга, в принципе, сейчас подходит, но, как говорит MSDN, будет ряд
ограничений (связаны с шифрованим и буферизацией, подробнее — в статье), из-за которых,
цитирую:


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


Если сейчас этим можно пренебречь, так как никакого шифрования нет и в помине, но
в разрезе дальнейшего развития сервиса это смущает.

Пока в качестве наиболее подходящих путей пытался как включать поддержку MTOM, так
и стриминг. 

Итак, в качестве пути решения был выбран проект WCF Service Library, в котором был
объявлен интерфейс службы, примерно так:

[ServiceContract]
public interface IUpdaterService
{
    [OperationContract]
    bool TestConnection();
    ... 
    [OperationContract]
    FileStream DownloadFile(string filename);
    ...
}


Ага, тут я использую FileStream, значит нужно включить поддержку стриминга, но сложность
в том, что я попросту не знаю, где и как это сделать. То же самое и с включением MTOM.

Ну, например, в попавшихся мне решениях говорят, "измените конфиг так":




    
        
            
        
    
    
        
    





Вроде всё понятно, что менять и на что, но где это делать?

Напоминаю, у меня DLL, в которой есть лишь App.config, и он - следующий:






  


  
  


  
    
      
        
          
        
      
      
      
        
          
        
      
    
  
  
    
      
        
        
      
    
  





Т.е. по сути, в App.config нет, например, раздела bindings, где можно было бы изменить
эти параметры.
При запуске родного WCF Test Client метод DownloadFile не доступен, так как используется
тип FileStram, стало быть, протестировать его никак...

Конфиг клиента, в свою очередь, формируется такой, нужно, т.е. как раз с теми разделами,
которые можно менять:




    
        
            
        
    
    
        
    





Но опять же - возникает вопрос - а где и как менять этот конфиг? Уверен, он генерируется
автоматически, т.е. необходимо задать нужные параметры для моей DLL, но как верно это
сделать? К сожалению, ответа на этот вопрос пока не нашел (может, плохо искал, конечно).

Спасибо.
    


Ответы

Ответ 1



Начну с конфигов. Во-первых, у DLL не бывает файла конфигурации. Тот, что у вас в проекте лежит - это мусор. Ну, некоторые настройки используются самой студией - на остальные же можно смотреть только как на пример. Файлы конфигурации бывают только у исполнимых файлов и у веб-сайтов. Далее - файл конфигурации не является автогенерируемым. Студия может в нем что-то менять - но как правило, это лишь пример. По-хорошему, вам надо пойти в msdn - и прочитать описание каждого тэга, используемого в вашем файле конфигурации. Секция bindings используется на обоих сторонах соединения - т.е. и клиентом, и сервером. Но она опциональна - без нее будут браться настройки по умолчанию. Если вам надо поменять там настройки, но ее нет - значит, ее надо создать. На разные привязки (bindings, "биндинги") ссылаются конечные точки (endpoint) через атрибуты binding и bindingConfiguration. Когда будете создавать свои привязки - не забудьте про эту связь, чтобы не удивляться потом что ничего не изменилось. Теперь про передачу файлов. Не переживайте особо про расширение в дальнейшем - когда понадобится сделать по-другому, всегда можно все перенастроить. По-меньше думайте "как сделать чтобы никогда не надо было переписывать" - а по-больше "какова моя задача сейчас?" Сериализация бинарных данных в XML недостатком не является пока эти файлы не очень большие. Просто помните, что файлы от этого распухают на треть. Шифрование на транспортном уровне не является проблемой если только вы не работаете с интеграционными шинами.

среда, 4 марта 2020 г.

При использовании NAT запросы к WCF проходят не корректно

#c_sharp #wcf #nat


Есть служба WCF, она хостится на порту 8888.

При использовании NAT 
outside 8888, inside 8888 - проходит отлично.
outside 2145, inside 8888 - проходит с ошибкой.
outside 5416, inside 8888 - проходит с ошибкой.

Т.е., если использовать одинаковые порты на входе и выходе запросы проходят.
Если они разные, тогда нет.

Служба 

Байндинг службы

  private static WSHttpBinding Setbinding()
    {
        WSHttpBinding binding = new WSHttpBinding();
        binding.Security.Mode = SecurityMode.None;
        return binding;
    }


Клиент

Код запроса 

  int PortNumber =2145;//или 5416 или 8888
  client = new PServiceClient(GetBinding(), 
  new EndpointAddress(string.Format("http://{0}:{1}/PService/", "168.211.65.22",
PortNumber)));
  ...
  //Проверка коннекта
  bool res = client.Connect();


Байндинг клиента

private WSHttpBinding GetBinding()
        {
            WSHttpBinding binding = new WSHttpBinding();
            binding.Security.Mode = SecurityMode.None;
            timeout = TimeOut.GetTimeOut();
            return binding;
        }


Почему у меня не работают корректно запросы к службе при использовании NAT?
    


Ответы

Ответ 1



Вы используете WSHttpBinding - а эта привязка подразумевает использование стандарта WS‑Addressing, который в свою очередь передает адрес принимающей стороны в заголовке To. Честно говоря, я не знаю зачем вообще в веб-сервисах, где отправитель и получатель сообщения всегда известны, использовать WS‑Addressing. Выглядит как глупость, и именно из-за нее SOAP считают довольно "тяжелым" протоколом. Поэтому самый простой способ - отказаться от WSHttpBinding и перейти на BasicHttpBinding, там такой проблемы нет. Если же вам требуется именно WSHttpBinding - то есть три пути. Самый правильный с точки зрения стандартов - рассказать серверу какой у него реальный адрес: var binding = new WSHttpBinding(); var internalUri = new Uri("http://192.168.1.10:8888/PService/"); var externalUri = new Uri("http://168.211.65.22:2145/PService/"); ServiceHost host = new ServiceHost(foo); host.AddServiceEndpoint(typeof(IFoo), binding, internalUri); host.AddServiceEndpoint(typeof(IFoo), binding, address: externalUri, listenUri: internalUri); Я добавил две конечные точки чтобы сервер мог принимать как прямые запросы так и запросы через NAT. Но хардкодить адреса - не лучшая идея, все же такие вещи лучше выносить в код: Тут главное - не перепутайте, address - это то что сервер будет ждать в заголовке To, сюда попадает тот адрес который видит клиент; listenUri же - этот тот адрес который реально слушает сервер. Альтернативный вариант - обучить клиент передавать правильные заголовки. Этот вариант не очень хороший, поскольку раскрывает перед клиентом внутреннюю структуру сети сервера. Но для полноты картины я его тоже приведу. var binding = new WSHttpBinding(); var internalUri = new Uri("http://192.168.1.10:8888/PService/"); var externalUri = new Uri("http://168.211.65.22:2145/PService/"); var client = new FooClient(binding, new EndpointAddress(internalUri)); client.Endpoint.EndpointBehaviors.Add(new ClientViaBehavior(externalUri)); Как я уже писал, адреса предпочтительнее задавать в конфиге. Для клиента это делается так: Как видно, уже чуть сложнее чем для сервера но все еще ничего страшного. Также допустим смешанный вариант. Дело в том, что от адреса конечной точки совершенно не требуется чтобы он был настоящим http-адресом! Все реальные http-адреса указываются в атрибутах listenUri и viaUri, к адресу же главное требование - совпадение у клиента и у сервера. А значит, туда можно написать любой uri, например какой-нибудь urn:local:my-cool-web-service (такой адрес обычно называют логическим адресом сервиса). Вот пример конфигов для сервера и клиента с настроенным логическим адресом: Достоинство этого варианта - ни клиент ни сервер ничего не знают о деталях трансляции адресов. Недостаток же этого варианта заключается в том, что если вы покажите такой конфиг стороннему разработчику, он может, э-э-э... слегка удивиться такому решению. Наконец, самый последний вариант. Самый простой, но костыль. Можно вовсе отключить проверку адреса на стороне сервера: [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)] class Foo : IFoo { }

среда, 29 января 2020 г.

Актуализация информации

#c_sharp #net #wcf #веб_программирование #клиент_сервер


Есть Клиент, который работает с WCF службой.

WCF служба в свою очередь предоставляет информацию из MS SQL БД.

Клиент может менять данные через WCF службу на SQL сервере.

Собственно вопрос, как правильно поддерживать данные на клиенте в актуальном состоянии?

На сколько верным решением будет каждые 5 минут по таймеру запрашивать у WCF службы
данные? Может быть есть более грамотный подход?
    


Ответы

Ответ 1



SQL Server может уведомлять WCF службу об изменениях в интересующих её таблицах. А служба, в свою очередь, уведомлять клиентов-подписчиков.

Ответ 2



По молодости была такая ошибка, при старте программы закачивал много данных с БД, потом написал обёртки к коллекциям, которые эти множества синхронизировали. При старте программа долго грузилась и было много ещё каких косяков. Согласен с @AdamSkywalker всё зависит от бизнес требований. Есть альтернативный подход. Загружать данные под конкретную операцию, к примеру нужно найти договор, не нужно загружать все 100500 договоров. А потом скролить и искать нужный договор. Это неправильно с точки зрения UX. Пользователь все равно в один момент времени не видит 100500 договоров. Загрузить 10 последних договоров и показать их пользователю. Он не нашел, ввел критерии поиска (фильтр + сортировка) и под этот фильтр запрашивается обозримое пользователем количество договоров, после того как он выбрал договор, всё это список не нужен, он выбрасывается из памяти.

четверг, 23 января 2020 г.

Как работать с общими данными в нескольких WCF сервисах?

#c_sharp #net #wcf


Допустим у нас есть 2 WCF сервиса, которые хостятся на сервере:


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


Как правильно в данной ситуации нужно действовать?
    


Ответы

Ответ 1



У дуплексных служб, колбеки от клиента прописываются в контракте. Когда клиент подключается, он передает свой контекст сервису и сервис получает через этот контекст доступ к колбекам клиента. Передача контекста между сервисами не предусмотрена, т.к. в зависимости от настроек сервиса создается отдельный инстанс сервиса на подключение или сессию для каждого клиента. Если ваше приложение использует больше одного сервиса в своей работе, то оно обязано подключаться к каждому из них независимо, таким образом необходимости в передаче контекста между службами просто не может быть.

воскресенье, 12 января 2020 г.

Выбор альтернативного сервиса при отказе основного.

#c_sharp #wcf #очередь #cluster


Реализуем кластерное решение для wcf сервисов. Подскажите есть ли какое-нибудь проверенное
решение для проверки доступности другого сервиса и выбора альтернативного, при отказе
основного. 
Например. 
На wcf сервис приходят сообщения от клиента и он их ставит в очередь. Очередь реализовала
на отдельном сервере и отдельным сервисом. Если этот сервис с очередью выйдет из строя,
нужно отправлять сообщения на резервный сервис, определенный заранее. Есть ли какие-то
красивые решения для реализации в автоматическом режиме по средствам wcf или проверять
в коде доступность одного сервиса и так далее?
    


Ответы

Ответ 1



Про штатные средства для подобных проверок в WCF я не слышал (точнее, слышал о WS-Discovery, начиная с .NET 4.0, но не пробовал и не уверен, что оно вообще подходит). Поэтому расскажу про велосипеды. Нужно быстро узнавать о падении стороннего сервиса Суть в периодическом "пинге" сервиса. Заводите таймер/отдельный поток, который проверяет доступность сервиса. Если сервис недоступен, имеет смысл сделать дополнительные 2-3 попытки с возрастающим интервалом между ними (как и в случае со всеми остальными методами), поскольку могут быть кратковременные перебои в сети. Если в итоге сервис не отвечает, производите операцию переключения (меняете адрес сервиса на дополнительный и делаете все остальные вещи, которые могут быть с этим связаны). Повторные попытки, само собой, нужно делать при получении определенных исключений (например, CommunicationException). Контроля над сторонним сервисом нет Если сервис не предлагает специально предназначенной для проверки статуса операции (типа Ping(), Heartbeat(), CheckStatus() и т.д.), то можно запрашивать его метаданные: bool isServiceUp = true; try { string address = "http://server/Service.svc?wsdl"; var mexClient = new MetadataExchangeClient( new Uri(address), MetadataExchangeClientMode.HttpGet); mexClient.GetMetadata(); } catch (Exception e) { // если сервис недоступен, получим исключение isServiceUp = false; } Контроль над сторонним сервисом есть В сервис добавляется "проверочный" метод (Ping()/Heartbeat()/CheckStatus()). В самом простом варианте этот метод пуст, но он также может возвращать и данные о своем состоянии (особенно если внутри себя он использует несколько разных систем - БД, другой сервис и т.д.). О падении сервиса достаточно узнавать в момент его вызова В этом случае все несколько проще, потому что вам не нужно специально проверять сервис. Если при очередном вызове сервиса он не ответил, пробуете еще 2-3 раза. Если после этого сервис не ответил, производите операцию переключения и снова пробуете сделать вызов. Какой бы вариант вы не выбрали, вам понадобятся следующие блоки: код переключения сервисов (как минимум подмена одного адреса на другой) обобщенный код повтора операций, чтобы любой метод можно было вызвать как InvokeWithRetry(() => SomeMethod()) обобщенный код, который соединяет эти два блока вместе и вызывает переключение сервисов в случае необходимости

суббота, 11 января 2020 г.

Как снизить уровень взаимодействия с сетью в WCF до Stream?

#wcf #c_sharp


Технология WCF хорошо решает проблему с брандмауэрами при разработке распределённых
приложений, так как предоставляет уровень абстракции над стандартными протоколами и
готовые механизмы аутентификации. Но нижний уровень упаковки данных в WCF - это контракты
данных. Мало того, что wsdl накладывает много ограничений на формат данных, так ещё
и эффективность xml-упаковки оставляет желать лучшего. Я сделал обёртку, чтобы надстроить
бинарный формат данных поверх xml, но это тоже не самое эффективное решение. Да, объём
передаваемых данных уменьшился примерно на порядок, исчезли падения на превышении немаленьких
квот при получении списка объектов на видимом прямоугольнике карты, но зато и перепаковка
выполняется дважды - сначала объектная модель сериализуется в бинарник, а потом бинарник
размазывается в xml. Когда операций перепаковки много, это заметно.
В идеале для сервисов внутреннего пользования (т.е., не предназначенных для интеграции
с внешними системами) вместо контрактов я бы хотел иметь Stream, который отвечает за
взаимодействие Endpoint'ов, разруливает поддержку стандартных сетевых протоколов и
аутентификацию, но в который можно писать / читать любые данные. То есть, я хотел бы
снизить уровень взаимодействия с сетью, но сохранив то хорошее, что есть в WCF. Поточные
контракты данных здесь не подходят, так как если сервис инстанцирован локально, никаких
перепаковок происходить не должно.
Есть ли статьи на эту тему?
Есть ли альтернативные технологии?
Может, есть настройки WCF, которые бы позволяли сериализовывать данные не через xml,
а прямо гонять сформированные бинарные массивы?    


Ответы

Ответ 1



В WCF можно собрать свой customBinding, включив туда альтернативный кодировщик сообщений. выглядит как то, что вам нужно.

Ответ 2



Если ты объявляешь метод с параметром Stream и/или возвращающий Stream, то ты можешь делать с потоком всё что угодно. Wcf поддерживает альтернативные сериализаторы, в том числе бинарные.

Ответ 3



Пока что в документации удалось найти вот это: Задание передачи данных в контрактах служб Большие наборы данных и потоковая передача Но тут немного смущает то, что там есть ограничения на способы обеспечения безопасности. Мы как раз используем шифрование сообщений. Впрочем, ограничение выглядит вполне логичным, надо будет придумать, как его обойти.

пятница, 10 января 2020 г.

Покупка сертификата для связи WCF

#windows #wcf #x509certificate


В течение долгого времени я использую "Makecert.exe", чтобы создать свой собственный
сертификат, используемый для связи WCF между двумя клиентами.
Но я получаю отчеты об ошибках от пользователей, которые имеют более высокие процедуры
безопасности/проверки, ошибки похожие на это:


  UntrustedRoot: A certificate chain processed, but terminated in a root
  certificate which is not trusted by the trust provider


Я хочу избавиться от этого и приобрести сертификат. Предпочтительно с очень длинным
срока годности. Но у меня остались вопросы:


Какой тип сертификата мне нужен? (Какое имя у этого типа сертификата?)
Где я могу купить это? Я был бы признателен, по крайней мере за одну
строку о том, как я могу проверить тип сертификата.


Используется Tcp и Pipe биндинги(в них и прописан сертификат) с поддержкой сессий
на основе callback вызовов.
Приложение у меня десктопное(сервер-много клиентов), тоесть это не веб сайт, я передаю
информацию между двумя приложениями.
    


Ответы

Ответ 1



Если используется http binding, то с серверной стороны должно хватить обычного single-domain https сертификата - т.к. от сервера при этом требуется лишь сертификат с Enhanced Key Usage: Server Authentication (1.3.6.1.5.5.7.3.1) Обычные провайдеры сертификатов добавляют еще и Client Authentication (1.3.6.1.5.5.7.3.2). Проверить, хватит или нет, можно сгенерировав такой сертификат самому: makecert -r -pe -n "CN= myserver " -b 01/01/2000 -e 01/01/2050 -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 Если с ним приложение заработает - то заработает и с сертификатом от https провайдера.

воскресенье, 22 декабря 2019 г.

В чем разница между MessageContract и DataContract в WCF?

#c_sharp #net #wcf


Когда используется одно, а когда другое?
С виду эти контракты очень похожи
    


Ответы

Ответ 1



В общих чертах: Соглашения (Contracts) в WCF предоставляют совместимость, необходимую для взаимодействия с клиентом. DataContract и MessageContract являются структурными соглашениями (structural contracts), которые дополняют друг друга и служат разным целям. DataContract - это соглашение между сторонами (сервисом и клиентом), которое описывает тип данных, которым они будут обмениваться, иными словами DataContract используется для определения структуры данных сообщения, т.е. DataContract определяет какие параметры и возвращаемые типы будут сериализованы/десериализованы Binary <==> XML для обмена между сторонами. WCF использует SOAP-сообщения для общения. MessageContract используется для контроля структуры тела SOAP-сообщения (SOAP message body) и сериализации данных, а так же для передачи информации в заголовках SOAP-сообщений (SOAP header). Таким образом, использование MessageContract предпочтительно только тогда, когда существует необходимость контролировать "макет" вашего сообщения (SOAP-сообщения). Например, добавить специфичные данные в Header SOAP-сообщения. Итого: В 90% случаев, использования DataContract будет достаточно для достижения поставленных целей, но если же вам необходимо очень тщательно контролировать "макет" вашего SOAP-сообщения, то тут на помощь приходит MessageContract.

пятница, 20 декабря 2019 г.

Разбить “класс-бог”

#c_sharp #wcf


В моём проекте есть сервис WCF, есть интерфейс описывающий ServiceContract (IMainHost),
и есть класс на основе этого интерфейса (MainHost). И всё отлично работает. Смущает
только одно - класс такого размера что студия тормозит когда я его редактирую. Создавать
ещё один сервис так себе вариант. Я его конечно могу сделать partial, но вдруг есть
какие то другие варианты? 
    


Ответы

Ответ 1



Делегирование (англ. Delegation) — основной шаблон проектирования, в котором объект внешне выражает некоторое поведение, но в реальности передаёт ответственность за выполнение этого поведения связанному объекту. Часть внутренней реализации MainHost вынести по смыслу в отдельные классы и использовать их внутри MainHost.

Ответ 2



Методы wcf-сервиса должны представлять собой всего несколько строк: [АтрибутДляКонтроляПравДоступа(какие, то, параметры)] public Метод(Его аргументы) { return КакойТоBll.Метод(аргументы); } Итого 6 строк (одна пустая) на метод. Остальное следует разложить по bll-классам.

среда, 18 декабря 2019 г.

Web Service для Linux-сервера на C#

#c_sharp #mono #wcf #service #linux


Я занимаюсь изучением возможности написания Web Service'a для Linux-сервера при использовании
C#. Для этого необходимо использовать Mono-Framework. Как я понял, WCF в Mono имплементирован
лишь относительно и у меня появилось чувство, что лучше не трогать его. Вроде бы и
все основные вещи должны работать, но что-то не то...

И я вот подумал, что может лучше стоило бы воспользоваться другими фрэймворками,
которые адаптированны под Mono. Я нашел несколько, но наиболее интересными мне показались
лишь 3: 


Nancy
ServiceStack
NServiceBus (не понятно, работает вообще под моно или нет, но вроде как должен.


Есть ли у кого нибудь опыт подобной разработки и что можно было бы для этого посоветовать?
Поделитесь опытом. 

Или лучше вообще отказаться от такого проекта? Клиент хочет, чтобы сервер работал
на Linux и на Windows без установки Tomcat (поэтому ява исключается).
    


Ответы

Ответ 1



попробуй ASP .NET, там есть asmx-файлы http://www.mono-project.com/archived/writing_a_webservice/ <%@ WebService Language="C#" Class="MathService.MathService" %> using System; using System.Web.Services; namespace MathService { [WebService (Namespace = "http://tempuri.org/NumberService")] public class MathService : WebService { [WebMethod] public int AddNumbers (int number1, int number2) { return number1 + number2; } [WebMethod] public int SubtractNumbers (int number1, int number2) { return number1 - number2; } } }

понедельник, 16 декабря 2019 г.

Asynchronous Operation in WCF

#c_sharp #wcf


Мне нужно выполнить background операцию, которая занимает много времени в моем WCF-сервисе.
Сервис не должен быть заблокирован во время выполнения этой операции. Вызов операции
происходит из контроллера.
Server Side:

[ServiceContract]
public interface IServiceContract
{
    [OperationContract]
    System.Threading.Tasks.Task GetMessages(int sleep);
}

public class HelloService : IServiceContract
{
    public async System.Threading.Tasks.Task GetMessages(int sleep)
    {
        var task = System.Threading.Tasks.Task.Factory.StartNew(() =>
        {
            Thread.Sleep(sleep);
            return "Return from Server after: " + sleep;
        });
        return await task.ConfigureAwait(false);
    }
}


Client side:

public partial class HelloServiceClient : ClientBase,
                                          IServiceContract {
   public System.Threading.Tasks.Task GetMessages(int sleep)
   {
       return Channel.GetMessages(sleep);
   }


Использование в контроллере:

    public async System.Threading.Tasks.Task GetResult(int sleep)
    {
       var client = DAACommunicationServiceHelper.CreateClient();
       SystemLogManager.Current.Write("Start GetResult: " + sleep);
       var result = await client.GetMessages(sleep);
       SystemLogManager.Current.Write("GetResult = " + result);
       SystemLogManager.Current.Write("End GetResult: " + sleep);
       return result;
    }


После этого я отправила 2 запроса:

POST https://localhost:44374/Services/Maintenance.asmx/GetResult HTTP/1.1
{"sleep":1000}


и сразу

POST https://localhost:44374/Services/Maintenance.asmx/GetResult HTTP/1.1
{"sleep":1}


Я ожидала что запрос "sleep":1 выполниться быстрее, но WCF-сервис был заблокирован
пока не выполнился запрос "sleep":10000.

Вот что в логах:

2017-06-14 11:25:16.1684 INFO Start GetResult: 10000
2017-06-14 11:25:19.3156 INFO Start GetResult: 1
2017-06-14 11:25:26.1802 INFO GetResult = Return from Server after: 10000
2017-06-14 11:25:26.1802 INFO End GetResult: 10000
2017-06-14 11:25:26.1802 INFO GetResult = Return from Server after: 1
2017-06-14 11:25:26.1802 INFO End GetResult: 1


UPD:
Почему WCF-сервис был заблокирован пока не выполнился запрос "sleep":10000? Мне нужно
чтобы WCF-сервис выполнял операцию асинхронно и запросы возвращались по мере выполнения. 
В логах я рассчитывала увидеть такое:

2017-06-14 11:25:16.1684 INFO Start GetResult: 10000
2017-06-14 11:25:19.3156 INFO Start GetResult: 1
2017-06-14 11:25:26.1802 INFO GetResult = Return from Server after: 1
2017-06-14 11:25:26.1802 INFO End GetResult: 1
2017-06-14 11:25:26.1802 INFO GetResult = Return from Server after: 10000
2017-06-14 11:25:26.1802 INFO End GetResult: 10000

    


Ответы

Ответ 1



Проверила на чистом проекте и заметила что на реальном проекте для сервиса было указано [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]. Проблема решилась добавлением ConcurrencyMode.Multiple

вторник, 10 декабря 2019 г.

Как WCF служба может узнать, что клиент отсоединился?

#c_sharp #wcf


Когда клиент хочет отредактировать запись, то шлется запрос WCF службе, что бы она
в свою очередь обновила статус этой записи в БД на "редактируется", что бы другие клиенты
с ней ничего не могли сделать на время редактирования.

Так вот, если неожиданно клиент отрубился(пропал интернет и все такое), как WCF служба
может узнать, что клиента, который производил редактирование, больше нет и нужно вернуть
статус на доступно?

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


Ответы

Ответ 1



Для этих целей лучше использовать класс IChannelInitializer - класс, предназначенный для детектирования подключения клиентов, в котором вы можете установить события на закрытие канала(чтобы не писать их в каждой реализации метода службы) Например, создадим класс ClientTrackerChannelInitializer, который наследует интерфейс IChannelInitializer. class ClientTrackerChannelInitializer : IChannelInitializer { internal static int ConnectedClientCount = 0; // метод, который определяет, что клиент подсоединился, создался новый канал public void Initialize(IClientChannel channel) { ConnectedClientCount++; Console.WriteLine("Client {0} initialized", channel.SessionId); channel.Closed += ClientDisconnected; channel.Faulted += ClientDisconnected; } // событие, на которое подписались при создании канала static void ClientDisconnected(object sender, EventArgs e) { Console.WriteLine("Client {0} disconnected", ((IClientChannel)sender).SessionId); ConnectedClientCount--; } } У него два метода Initialize - метод, который срабатывает при подключении нового клиента ClientDisconnected - метод, обработчик события закрытия канала(или ошибки в канале) Теперь необходимо подключить класс ClientTrackerChannelInitializer на стороне сервера. Для этого создадим класс, реализующий интерфейс IEndpointBehavior, класс, который позволяет расширять поведение конечной точки службы class ClientTrackerEndpointBehavior : IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { // подключаем наш класс endpointDispatcher.ChannelDispatcher.ChannelInitializers.Add(new ClientTrackerChannelInitializer()); } public void Validate(ServiceEndpoint endpoint) { } } В методе ApplyDispatchBehavior мы подключили класс ClientTrackerChannelInitializer. Все классы созданы. Теперь можно публиковать службу. Предположим, что у нас есть сервис IStackCalculator. Класс StackCalculator реализует данный сервис [ServiceContract(SessionMode = SessionMode.Required)] public interface IStackCalculator { [OperationContract] void Enter(double value); [OperationContract] double Add(); [OperationContract] double Subtract(); [OperationContract] double Multiply(); [OperationContract] double Divide(); } Теперь при публикации хоста сервиса подключим наше расширение конечной точки. string baseAddress = "http://" + Environment.MachineName + ":8000/Service"; ServiceHost host = new ServiceHost(typeof(StackCalculator), new Uri(baseAddress)); WSHttpBinding binding = new WSHttpBinding(SecurityMode.None); binding.ReliableSession.Enabled = true; ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IStackCalculator), binding, ""); // подключаем расширение конечной точки службы endpoint.Behaviors.Add(new ClientTrackerEndpointBehavior()); host.Open(); Console.WriteLine("Host opened"); Теперь при соединении/отключении клиентов будут срабатывать события Initialize и ClientDisconnected нашего класса ClientTrackerChannelInitialize. Нет необходимости прописывать подписывание на событие закрытия канала в самой реализации метода. Механизм создания классов-расширения служб, реализующих интерфейс IEndpointBehaviour, можно применять для многих целей. По своему опыту применял для подсчета количества вызовов функций сервиса, для замера скорости выполнения функции сервиса, для аутентификации пользователя... Посмотрите Примеры использования IEndpointBehavior. Более подробно о примере, который мы рассмотрели, можно прочитать здесь. Пример кода P.S. Если необходимо подключить кастомный IEndpointBehavior через файл config, напишите, добавлю в ответ. Edit: Чтобы подключить наш класс-расширение конечной точки ClientTrackerEndpointBehavior, мы должны сделать следующее Зарегистрировать наше поведение в < system.servicemodel >/< extensions >/< behaviorExtensions > указав имя расширения и тип класса, реализующего расширение(тип класса ClientTrackerEndpointBehavior) < extensions > < behaviorExtensions> < add name="clientTracker" type="ClientTrackerEndpointBehavior, Client.ExtensionsDLL /> < /behaviorExtensions> Добавить расширение конечной точки в элементе < behaviors >. Здесь мы в качестве расширения указываем элемент-расширение clientTracker, которое определили на предыдущем шаге < behaviors> < endpointBehaviors> < behavior name="ServiceBehaviorExtension"> < clientTracker /> < /behavior> < /endpointBehaviors> < /behaviors> Теперь при определении конечной точки сервиса мы можем подключить поведение через атрибут behaviourConfiguration, указав имя расширения, указанного выше < services> < service name="StackCalculator" > < endpoint name="endpoint1" address="" binding="basicHttpBinding" bindingName="binding" contract="IStackCalculator" behaviorConfiguration="ServiceBehaviorExtension" / > ... < /services > Пример можно посмотреть например отсюда

Ответ 2



Вам нужен элемент привязки reliableSession. Этот элемент привязки, помимо прочих функций, периодически посылает сообщения для поддержания соединения в активном состоянии. У элемента привязки reliableSession есть настройка inactivityTimeout. Она задает период времени, в течении которого этот элемент ожидает сообщений с другого конца соединения прежде чем сказать что соединение закрылось. При этом сам он периодически посылает "пустые" сообщения для поддержания соединения. Внимательнее будьте с настройкой receiveTimeout. Она задает интервал времени, в течении которого сервис ожидает хоть одного непустого сообщения. Значение здесь должно быть как минимум раз в десять выше, чем значение inactivityTimeout - иначе весь смысл reliableSession теряется. UPDATE Теперь как отслеживать соединение/отсоединение клиента. Самый простой способ - использовать [ServiceContract(SessionMode = SessionMode.Required)] и [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)], при этом реализовать интерфейс IDisposable. При подключении нового клиента будет вызван конструктор сервиса, при отключении (нормальном либо аварийном) - метод Dispose(). UPDATE Пример фрагмента конфига привязки: Достаточно настройки привязки, остальные настройки менять не нужно. Настройки привязки на клиенте и сервере должны совпадать (либо быть совместимы - но проще чтобы совпадали). Скорее всего, у вас binding будет иметь также атрибут name. Атрибут ordered="false" не обязателен, привел его для примера. Он отвечает за то, будет ли reliableSession следить за порядком сообщений.

Ответ 3



Как вариант клиенту дергать метод WCF службы, который говорит, что "вот я в сети" с периодичностью скажем 5-15 минут. Если инет падает у клиента, он метод не дергает, а значит служба через 5-15 минут меняет в БД статус. Дополнение к ответу Можно прочекать отвалился ли клиент так: using System; using System.ServiceModel; namespace WcfServiceLibrary1 { public class Service1 : IService1 { public string GetData(int value) { ClientConnected(); return string.Format("You entered: {0}", value); } private void ClientConnected() { IContextChannel objClientHandle = OperationContext.Current.Channel; objClientHandle.Faulted += new EventHandler(this.ClientDisconnected); } private void ClientDisconnected(object sender, EventArgs e) { var context = (IContextChannel)sender; // вот тут будет понятно, что клиент отрубился. // Тестил я так - установил таймаут на биндинге - называется он в конфиге. // Через 15 сек клиент отваливается и кидает сюда. } } } Вот на всякий случай как прописать таймаут, чтобы протестить, с реальным дисконнектом не тестил:

понедельник, 9 декабря 2019 г.

Как грамотно завершить работу self hosted wcf службы?

#c_sharp #net #wcf #windows_service


Допустим есть wcf служба, которая хостится в win service.

Если пользователь решит вырубить сервис, то как мне грамотно завершить работу wcf
службы? 

Допустим, один юзер вызвал метод по перемещению файлов, другой юзер что-то делает
с базой.

Если без логики завершить работу Win Service, то это приведет к необратимым последствиям.
    


Ответы

Ответ 1



Можно попробовать при остановке Win Service сигналить в WCF Service с помощью CancellationToken о том, что Win Service собирается останавливаться. WCF Service внутри себя должен проверять состояние данного CancellationToken, и, если запрошена отмена, выдавать исключение для вновь запрашиваемых операций, а уже выполняющиеся, например, прерывать. Win Service должен дождаться завершения отмены активных операций выполняемых WCF Service. Для отслеживания этого в WCF Service можно, к примеру, использовать ManualResetEvent и счётчик активных операций. Ниже примерная реализация (с достаточным числом упрощений). Контракт: [ServiceContract] public interface IWCFService { [OperationContract] string Echo(string str); } WCF Service: public class WCFService : IWCFService { CancellationToken ctOperations; public WCFService() { //у WinService берём CancellationToken остановки операций ctOperations = MyService.GetOperationsCancellationToken(); } public string Echo(string str) { //не выполняем новые операции, если началась остановка if (ctOperations.IsCancellationRequested) throw new Exception("Service stopping."); try { //увеличиваем счётчик активных операций IncActiveCnt(); //имитация деятельности int i = 0; while (i++ < 10) { ctOperations.ThrowIfCancellationRequested(); Thread.Sleep(500); } return "Echo " + str; } catch (OperationCanceledException) { throw new Exception("Service stopping."); } catch (Exception) { throw; } finally { //уменьшаем счётчик активных операций DecActiveCnt(); } } static object lockObj = new object(); static int activeOperationCnt = 0; static ManualResetEvent evtNoActiveOperations = new ManualResetEvent(true); //свойство для проверки в WinService static public ManualResetEvent NoActiveOperations { get { return evtNoActiveOperations; } } private void DecActiveCnt() { lock (lockObj) { if (--activeOperationCnt == 0) //сигналим, если нет активных операций evtNoActiveOperations.Set(); } } private void IncActiveCnt() { lock (lockObj) { activeOperationCnt++; //сбрасываем сигнал, если есть активные операции evtNoActiveOperations.Reset(); } } } Win Service (в данном примере не внешнее приложение, а он сам себе является клиентом WCF Service): public class MyService : ServiceBase { static CancellationTokenSource ctsOperations = null; static ServiceHost svcHost = null; public MyService() { } protected override void OnStart(string[] args) { //токен для остановки операций ctsOperations = new CancellationTokenSource(); svcHost = new ServiceHost(typeof(WCFService)); svcHost.Open(); //запускаем клиента WCF Service ThreadPool.QueueUserWorkItem(UseWCFService); //ждём 13 сек. Thread.Sleep(13000); //теперь остановим Win Service Stop(); } protected override void OnStop() { //сигналим отмену операций ctsOperations.Cancel(); int msecExtend = 3000; RequestAdditionalTime(msecExtend); //ждём завершение отмены операций WCFService.NoActiveOperations.WaitOne(msecExtend); svcHost.Close(); ctsOperations.Dispose(); } public static CancellationToken GetOperationsCancellationToken() { return ctsOperations.Token; } private void UseWCFService(object state) { //имитируем клиента Uri tcpUri = new Uri(@"http://localhost:8733/WCFService/"); EndpointAddress address = new EndpointAddress(tcpUri); BasicHttpBinding binding = new BasicHttpBinding(); ChannelFactory f = new ChannelFactory(binding, address); IWCFService svc = f.CreateChannel(); int i = 0; while (!ctsOperations.IsCancellationRequested) try { string echo = svc.Echo((++i).ToString()); Console.WriteLine(echo); } catch { Console.WriteLine("Error"); } } }

Ответ 2



Немножко обобщу и дополню ответ @i-one. Для того чтобы корректно завершать сервис, нужно две вещи: уметь сообщать нужному коду о том, что пора закругляться дожидаться пока этот код завершит свое исполнение Сигнализировать о сообщении можно разными способами, самый разумный -- CancellationToken, который при старте передается всему необходимому коду. Дожидаться завершения исполнения тоже можно разными способами. В случае с потоками/синхронным исполнением -- @i-one привел рецепт. В случае если приложение полностью асинхронное (с использованием async/await), в винсервисе на запуске запоминается таск, а на стопе этот таск await'ится. Еще один момент, который стоит упомянуть: по умолчанию, Service Console Manager выделяет 30 секунд на то, чтобы сервис завершился (если это значение не было переопределено в реестре). Если сервис не уложился в отведенное время, то в консоли он помечается как остановленный, но процесс при этом продолжает работать, что не очень корректно. Если корректное завершение требует много времени, то можно запросить дополнительное время -- вплоть до 125 секунд в сумме: protected override void OnStop() { int timeout = 10000; while (!mainTask.Wait(timeout)) { RequestAdditionalTime(timeout); } } Однако в любом случае полезно иметь некий общий таймаут (например, 120 секунд) и завершать работу принудительно (если вдруг какой-то код завис).

вторник, 16 июля 2019 г.

Как заставить WCF не подменять SecurityException

Столкнулся с такой проблемой. Если я на сервере, внутри метода службы бросаю SecurityException с сообщением, которое хочу отобразить пользователю на клиенте, это исключение заменяется на FaultException с сообщением "Отказано в доступе". Причём в таком виде оно доходит не только до клиента, но уже до реализации IErrorHandler, подсунутой хосту. Если бросить не SecurityException, а его наследника - результат тот же самый. Понятно, что можно бросать другой тип исключения, объявленный в контракте сбоев, но если по семантике это SecurityException, такое решение не вполне корректно.


Ответ

Чтобы объект типа SecurityException пробрасывался на сторону клиента его нужно прописать в интерфейсе контракта при помощи атрибута FaultContractAttribute
[ServiceContract] public interface IServiceContract { [OperationContract] [FaultContractAttribute(typeof(SecurityException))] void CallMethod(); }

Два сервиса на одном сервере

Добрый день!
Спасибо что зашли. Я столкнулся с такой задачей.
Есть сервер, на нем установлены в IIS 4 WCF-сервиса:
Service1 : 1100 (основной) Service2 : 1101 Service3 : 1102 Service4 : 1103
Первый сервис вызывает второй. В принципе тут не было бы ничего сложного, если бы не сертификаты. Это сделано для того, чтобы софт. могли юзать только авторизованные приложения.
Ошибка при вызове сервиса 2:
System.ServiceModel.Security.SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority ':1101'. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
Я проверил сертификаты - мы заходим на второй сервис с нужным сертификатом. У меня есть подозрения, что ошибка в веб-конфиге.
Подскажите, пожалуйста, как решить эту проблему? Я с сертификатами только начинаю работать.
Ниже находится мой веб-конфиг:









Ответ

Могу дать три рекомендации на сей счет:
Всегда обновляться в Service References ссылку на сервис после его апдейта на сервере проверяйте доступ пользователя, под которым запущен Пул, к физической папке сервиса проверьте сертификаты и ендпоинты
Мне это помогло.

понедельник, 15 июля 2019 г.

Сервер рандомно падает с ошибкой

Пишу програмку на C# с использованием WCF. рандомно сервер падает с ошибкой:

кроме скриншрта, не могу получить информации, т.к. баг происходит в не менеджмент коде и сервак виснет в ожидании мертвого потока. исключение по стэку не поднимается, и отловить его не могу. я понимаю, что информации маловато, но очень прошу помощи, т.к. идеи кончились и гугление не дало результатов.
пишите, какую информацию предоставить... OS: Windows Server 2008 R2 ENT Framework 4.5.2


Ответ

помог переход на 2012 сервер. UseSynchronizationContext =false. всем спасибо.