Сообщений 1 Оценка 0 Оценить |
Введение WCF клиент WCF сервер Заключение Список литературы |
При разработке корпоративных Silverlight (WCF) приложений очень часто допускается ошибка проектирования, связанная с отсутствием поддержки прокси-серверов. Эта ошибка является следствием того, что приложения, написанные с использованием предыдущих web-технологий, таких как ASP.NET, PHP, PERL и др., не нуждались в какой-либо специальной реализации функциональности поддержки прокси-серверов, за исключением случаев абсолютной адресации внутри приложения, что не являлось частой ситуацией. Тем не менее, корпоративные web-приложения редко используются напрямую, и переадресация запросов ISA серверами или системами распределения нагрузки с автоматическим изменением протоколов c https на http и наоборот является распространенной практикой. В данной статье будет продемонстрирован подход, не претендующий на универсальность, но позволяющий избежать многих проблем.
Любое WCF-приложение имеет клиентскую часть, осуществляющую связь с серверной частью, являющейся набором WCF-сервисов. Но на пути следования запросов и отклика на них могут находиться различные системы, изменяющие адреса. Такими системами могут являться системы распределения нагрузки или прокси-сервера, такие как ISA-сервера. В некоторых случаях возможно комбинирование этих систем. Более того, может изменяться не только адрес, но и протокол, например с HTTP на HTTPS и наоборот. Такие сложные системы часто появляются вследствие политик безопасности компаний, и потому корпоративное WCF приложение должно поддерживать эти конфигурации. Для программистов клиентских приложений это означает отсутствие заранее определенного протокола связи с серверной частью и заранее определенных адресов WCF-сервисов.
Как правило, любое WCF-ориентированное приложение имеет конфигурационный файл с описанием всех настроек сервисов, с которыми осуществляется связь.
<configuration> <system.serviceModel> <client> <endpoint binding="customBinding" contract="CONTRACT"name="NAME" /> </client> </system.serviceModel> </configuration> |
Как можно видеть из приведенного XML, в нем не определяются специфические параметры связи с WCF-сервисом. Это сделано специально, чтобы приложение не зависело от какого-либо конкретного протокола. Все дополнительные параметры вынесены в код, где они динамически определяются и подставляются.
namespace WCFServices { using System; using System.ComponentModel.Composition; [Export(typeof(ICustomLoginService))] publicclass SecurityService : ICustomLoginService { privatereadonly CookieContainerWrapper _cookieContainerWrapper; privatereadonly LoginClient _client; [ImportingConstructor] public SecurityService(CookieContainerWrapper cookieContainerWrapper) { _cookieContainerWrapper = cookieContainerWrapper; _client = new LoginClient(new CustomBinding("CustomBinding_LoginClient", "", new BindingElement[] { new BinaryMessageEncodingBindingElement (), HtmlPage.Document.DocumentUri.Scheme.ToLower().Equals("https")? new HttpsTransportBindingElement (){MaxReceivedMessageSize=2147483647}: new HttpTransportBindingElementt(){ MaxReceivedMessageSize=2147483647, MaxBufferSize=2147483647} }), new EndpointAddress ("../Services/LoginService.svc")); _client.LoginCompleted += (s, e) => { var userCallback = e.UserState as Action<bool, CustomException, Exception>; if (e.Error != null) { var customError = e.Error as CustomException; if (customError != null) { var securityFault = customError.Detail; userCallback(false, customError, null, null); return; } var exception = e.Error as Exception; if (exception != null) { userCallback(false, null, exception, null); return; } userCallback(false, null, null, e.Error); return; } userCallback.Invoke(e.Result, null, null, null); return; }; } publicvoid Login(string login, string password, Action<bool, CustomException, Exception> callback) { _client.LoginAsync(login, password, callback); } } } |
Данный код осуществляет асинхронное взаимодействие сервисов, и именно здесь определяются все необходимые параметры для их связи. Опустим описание стандартных механизмов MEF и остановимся только на существенных деталях.
Наиболее интересным моментом в данном коде является создание объекта связи с сервисом _client. Как можно видеть, при задании протокола связи определяется схема, по которой было вызвано приложение. Для этого используется статическое свойство класса HtmlPage.DocumentUri.Scheme. В зависимости от того, какой адрес использовал пользователь для загрузки приложения(HTTP или HTTPS), подставляется HTTP- или HTTPS -транспорт, кроме того, используется относительный путь к сервису, что позволяет поддерживать случаи переписывания адресов системами распределения нагрузки.
Следующей возможной проблемой может оказаться неправильная настройка среды конечного пользователя. Это может быть что угодно, вплоть до не установленного WCF или любой проблемы с сетью. Службе поддержки будет крайне сложно определить причину без какой-либо дополнительной информации со стороны приложения. Как правило, на сервере ведется логирование всех исключений и даже регулярных транзакций, но проблема может быть и не в серверной части, и даже не в приложении. Тем не менее, задача приложения – облегчить работу службы поддержки насколько это возможно. Для этого стоит добавить логирование на стороне клиента. Как видно из приведенного выше кода, шаблон объекта Action содержит последние 2 аргумента, передающие исключения:
Следующий шаг конфигурирования WCF-ориентированного приложения – это серверная часть. Здесь уже не имеет особого значения, по какому протоколу, через какие прокси-сервера идет запрос к сервисам. Все что необходимо сделать для корректной работы приложения это правильно сформировать endpoint адреса сервисов и указать правильные протоколы передачи и кодировки данных. Из постановки задачи следует, что сервисы должны одновременно работать по протоколам HTTP и HTTPS. Таким образом, логично предположить, что необходимо наличие как минимум двух endpoint-адресов на каждый сервис, один для протокола HTTP, другой для протокола HTTPS и, соответственно, две конфигурации customBinding.
<system.serviceModel> <bindings> <customBinding> <binding name="silverlightBinaryBindingSSL"> <binaryMessageEncoding> </binaryMessageEncoding> <httpsTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"> </httpsTransport> </binding> <binding name="silverlightBinaryBinding"> <binaryMessageEncoding> </binaryMessageEncoding> <httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"> </httpTransport> </binding> </customBinding> </bindings> <services> <service name="LoginService"> <endpoint address="http://.../Services/LoginService.svc" listenUri="/" binding="customBinding" bindingConfiguration="silverlightBinaryBinding" contract="ILoginService" /> <endpoint address="https://.../Services/LoginService.svc" listenUri="/" binding="customBinding" bindingConfiguration="silverlightBinaryBindingSSL" contract="ILoginService" /> </service> </services> <behaviors> <endpointBehaviors> <behavior name="Personec.Negotiation.Web.Services.WindowDataServiceAspNetAjaxBehavior"> <enableWebScript> </enableWebScript> </behavior> </endpointBehaviors> <serviceBehaviors> <behavior name="MetadataEnabled"> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" /> </behavior> </serviceBehaviors> </behaviors> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"> </serviceHostingEnvironment> </system.serviceModel> |
Выше приведена секция ServiceModel из web.config файла. Как и прежде, остановимся лишь на существенных деталях:
Здесь есть одна существенная деталь – объявляя одновременно HTTP- и HTTPS-адреса, необходимо разрешить IIS использовать HTTPS.
Для этого необходимо:
В данной статье был описан один из возможных подходов к реализации WCF-ориентированных приложений, работающих через ISA-серверы и системы распределения нагрузки. Следуя данным рекомендациям, можно избежать многих проблем с поддержкой. Кроме того, перед началом проектирования приложения стоит выяснить как можно больше случаев специфических окружений, с которыми предстоит работать приложению, и постараться выбрать универсальный подход. Разумеется, можно создавать различные xap-файлы и серверные сборки, которые будут решать проблемы специфического окружения, и устанавливать их инсталлятором в нужных случаях, но следует помнить правило: не создавать лишних сущностей без крайней необходимости, иначе поддержка и обновление таких приложений может превратиться в непосильную задачу.
Сообщений 1 Оценка 0 Оценить |