Сделать WCF проще для настройки

У меня есть набор веб-сервисов WCF, динамически подключаемых настольным приложением.

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

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

Я хочу, чтобы настольное приложение было намного проще настроить - в идеале это было какое-то автоматическое обнаружение. Пользователи настольного приложения должны просто иметь возможность вводить URL-адрес, а остальные делать.

Кто-нибудь знает хороший способ сделать это?

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

Я знаю, что VS-инструменты могут использоваться извне, но я ищу пользователей настольных приложений, которые не должны быть экспертами WCF. Я знаю, что МС сделал это намеренно более сложным.

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

Ответы

Ответ 1

Вся информация о конечной точке доступна в метаданных службы, вы можете написать клиенту, что будет изучать метаданные службы и настроить клиента. Для примера кода вы можете посмотреть этот отличный Mex Explorer от Juval Lowy.

Ответ 2

Спасибо, это был полезный код (+1).

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

Я взял из него фактический механизм открытия, перезаписал его и почти получил его работу (подключается, но нуждается в некоторой утонченности).

Сначала некоторые функции использования, используемые основным методом:

/// <summary>If the url doesn't end with a WSDL query string append it</summary>
static string AddWsdlQueryStringIfMissing( string input )
{
    return input.EndsWith( "?wsdl", StringComparison.OrdinalIgnoreCase ) ?
        input : input + "?wsdl";
}

/// <summary>Imports the meta data from the specified location</summary>
static ServiceEndpointCollection GetEndpoints( BindingElement bindingElement, Uri address, MetadataExchangeClientMode mode )
{
    CustomBinding binding = new CustomBinding( bindingElement );
    MetadataSet metadata = new MetadataExchangeClient( binding ).GetMetadata( address, mode );
    return new WsdlImporter( metadata ).ImportAllEndpoints();
}

Затем метод, который пытается по-разному подключить и вернуть конечные точки:

public static ServiceEndpointCollection Discover( string url )
{
    Uri address = new Uri( url );
    ServiceEndpointCollection endpoints = null;

    if ( string.Equals( address.Scheme, "http", StringComparison.OrdinalIgnoreCase ) )
    {
        var httpBindingElement = new HttpTransportBindingElement();

        //Try the HTTP MEX Endpoint
        try { endpoints = GetEndpoints( httpBindingElement, address, MetadataExchangeClientMode.MetadataExchange ); }
        catch { }

        //Try over HTTP-GET
        if ( endpoints == null )
            endpoints = GetEndpoints( httpBindingElement,
                new Uri( AddWsdlQueryStringIfMissing( url ) ), MetadataExchangeClientMode.HttpGet );
    }
    else if ( string.Equals( address.Scheme, "https", StringComparison.OrdinalIgnoreCase ) )
    {
        var httpsBindingElement = new HttpsTransportBindingElement();

        //Try the HTTPS MEX Endpoint
        try { endpoints = GetEndpoints( httpsBindingElement, address, MetadataExchangeClientMode.MetadataExchange ); }
        catch { }

        //Try over HTTP-GET
        if ( endpoints == null )
            endpoints = GetEndpoints( httpsBindingElement,
                new Uri( AddWsdlQueryStringIfMissing( url ) ), MetadataExchangeClientMode.HttpGet );
    }
    else if ( string.Equals( address.Scheme, "net.tcp", StringComparison.OrdinalIgnoreCase ) )
        endpoints = GetEndpoints( new TcpTransportBindingElement(), 
            address, MetadataExchangeClientMode.MetadataExchange );

    else if ( string.Equals( address.Scheme, "net.pipe", StringComparison.OrdinalIgnoreCase ) )
        endpoints = GetEndpoints( new NamedPipeTransportBindingElement(), 
            address, MetadataExchangeClientMode.MetadataExchange );

    return endpoints;
}

Ответ 3

Теперь есть другой способ сделать это, который недоступен, когда я задал исходный вопрос. Microsoft теперь поддерживает REST для служб WCF.

  • Недостатком использования REST является то, что вы теряете WSDL.
  • Верхняя сторона - минимальная конфигурация, и ваши интерфейсы контракта WCF все равно будут работать!

Вам понадобится новая ссылка на System.ServiceModel.Web

Отметьте свои операции с помощью WebInvoke или WebGet

//get a user - note that this can be cached by IIS and proxies
[WebGet]
User GetUser(string id )

//post changes to a user
[WebInvoke]
void SaveUser(string id, User changes )

Добавление их на сайт легко - добавьте файл .svc:

<%@ServiceHost 
   Service="MyNamespace.MyServiceImplementationClass" 
   Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>

Строка factory сообщает ASP.net, как активировать конечную точку - вам не нужна никакая конфигурация на стороне сервера!

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

var cf = new WebChannelFactory<IMyContractInterface>();
var binding = new WebHttpBinding();

cf.Endpoint.Binding = binding;
cf.Endpoint.Address = new EndpointAddress(new Uri("mywebsite.com/myservice.svc"));
cf.Endpoint.Behaviors.Add(new WebHttpBehavior());

IMyContractInterface wcfClient = cf.CreateChannel();

var usr = wcfClient.GetUser("demouser");
// and so on...

Заметьте, что я не указал или не обнаружил конфигурацию клиента - там не нужна локальная конфигурация!

Еще один большой потенциал заключается в том, что вы можете легко переключиться на сериализацию JSON, что позволяет потреблять одни и те же услуги WCF Java, ActionScript, Javascript, Silverlight или что-то еще, что легко может обрабатывать JSON и REST.