Pergunta

Eu tenho um conjunto de serviços web WCF ligados ao dinamicamente por um aplicativo de desktop.

O meu problema é as definições de configuração realmente detalhados que WCF exige ao trabalho. Obtendo SSL para trabalho envolve configurações personalizadas. Obtendo MTOM ou qualquer outra coisa para o trabalho exige mais. Você quer que a compressão? Aqui vamos nós de novo ...

WCF é realmente poderoso - você pode usar uma série de maneiras diferentes para se conectar, mas todos parecem envolver lotes de configuração detalhada. Se o host eo cliente não correspondem perfeitamente você ficar difícil de erros decifrar.

Eu quero fazer o aplicativo de desktop muito mais fácil de configurar - idealmente algum tipo de auto-descoberta. Os usuários do aplicativo de desktop deve apenas ser capaz de digitar a URL e fazer o resto.

Alguém sabe uma boa maneira de fazer isso?

Eu sei que Visual Studio pode definir a configuração para você, mas eu quero o aplicativo de desktop para ser capaz de fazê-lo com base em uma ampla variedade de set-ups diferente do servidor.

Eu sei que as ferramentas do VS pode ser usado externamente, mas eu estou olhando para os usuários dos aplicativos de desktop para não ter que ser especialistas WCF. Sei MS fez isso intencionalmente mais complicado.

Existe alguma maneira, mecanismo, biblioteca parte 3 ou qualquer coisa para fazer auto-descoberta do WCF configurações possível?

Foi útil?

Solução

Todas as informações sobre o ponto final está disponível em metadados de um serviço, você pode escrever um cliente que vai explorar os metadados do serviço e configurar o cliente. Para um exemplo de código que você pode olhar para este excelente Mex Explorador partir Juval Lowy.

Outras dicas

Graças, que foi código útil (+1).

É mais do que um pouco confuso pouco, porém, tem alguns bugs (cheques sensíveis de casos que não deveriam estar, por exemplo), tem uma carga de funcionalidade UI que eu não preciso e repete um monte de código.

Eu tenho tomado dele o mecanismo de descoberta real, re escreveu-lo e quase tenho que trabalhar (se conecta, mas precisa de algum finessing).

Primeiro alguns util funções utilizadas pelo método principal:

/// <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();
}

Em seguida, um método que tenta maneira diferente de se conectar e retorna os endpoints:

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;
}

Existe agora uma outra maneira de fazer isso que não estava disponível quando eu perguntei a pergunta original. Microsoft agora suporta REST para serviços WCF.

  • A desvantagem de usar REST é que você perde a WSDL.
  • A vantagem é mínima config e suas interfaces contrato WCF ainda vai trabalho!

Você vai precisar de uma nova referência para System.ServiceModel.Web

Marque suas operações com qualquer WebInvoke ou 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 )

Adicionando estes a um site é fácil - adicionar um arquivo .svc:

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

A linha de fábrica diz ASP.net como ativar o ponto final - você não precisa de configuração do lado do servidor em todos

Em seguida, construir o seu ChannelFactory é praticamente inalterada, exceto que você não precisa especificar um ponto final mais (ou auto-descobrir um como eu tenho em outras respostas)

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...

Note que eu não tenha especificado ou descoberto a configuração cliente - não há nenhuma configuração locais necessárias

Outra grande vantagem é que você pode facilmente mudar para serialização JSON -. Que permite que os mesmos serviços WCF para ser consumido por Java, ActionScript, JavaScript, Silverlight ou qualquer outra coisa que pode lidar com JSON e descanso facilmente

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top