Exemplo mínimo de pipe nomeado do WCF


90

Estou procurando um exemplo mínimo de Pipes nomeados do WCF (espero dois aplicativos mínimos, servidor e cliente, que podem se comunicar por meio de um canal nomeado).

A Microsoft tem o brilhante artigo Getting Started Tutorial que descreve o WCF via HTTP, e estou procurando algo semelhante sobre WCF e pipes nomeados.

Encontrei vários posts na Internet, mas são um pouco "avançados". Preciso de algo mínimo, apenas funcionalidade obrigatória, para poder adicionar meu código e fazer o aplicativo funcionar.

Como faço para substituir isso para usar um pipe nomeado?

<endpoint address="http://localhost:8000/ServiceModelSamples/Service/CalculatorService"
    binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICalculator"
    contract="ICalculator" name="WSHttpBinding_ICalculator">
    <identity>
        <userPrincipalName value="OlegPc\Oleg" />
    </identity>
</endpoint>

Como faço para substituir isso para usar um pipe nomeado?

// Step 1 of the address configuration procedure: Create a URI to serve as the base address.
Uri baseAddress = new Uri("http://localhost:8000/ServiceModelSamples/Service");

// Step 2 of the hosting procedure: Create ServiceHost
ServiceHost selfHost = new ServiceHost(typeof(CalculatorService), baseAddress);

try
{
    // Step 3 of the hosting procedure: Add a service endpoint.
    selfHost.AddServiceEndpoint(
        typeof(ICalculator),
        new WSHttpBinding(),
        "CalculatorService");

    // Step 4 of the hosting procedure: Enable metadata exchange.
    ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
    smb.HttpGetEnabled = true;
    selfHost.Description.Behaviors.Add(smb);

    // Step 5 of the hosting procedure: Start (and then stop) the service.
    selfHost.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.
    selfHost.Close();
}
catch (CommunicationException ce)
{
    Console.WriteLine("An exception occurred: {0}", ce.Message);
    selfHost.Abort();
}

Como faço para gerar um cliente para usar um pipe nomeado?


Respostas:


80

Acabei de encontrar este excelente pequeno tutorial . link quebrado ( versão em cache )

Eu também segui o tutorial da Microsoft, o que é bom, mas também precisava apenas de pipes.

Como você pode ver, você não precisa de arquivos de configuração e todas essas coisas complicadas.

A propósito, ele usa HTTP e pipes. Apenas remova todas as linhas de código relacionadas ao HTTP e você obterá um exemplo de pipe puro.


2
Obrigado! Além disso, ao tentar criar um serviço que usa o web.config para sua configuração em vez da configuração codificada, consulte este exemplo da microsoft: msdn.microsoft.com/en-us/library/ms752253.aspx
Nullius

3
O link não funciona, o tutorial está em outro lugar?
user1069816

Só passei um tempo tentando descobrir por que o "tubo foi encerrado". Aqui está minha solução para isso, espero que ajude: stackoverflow.com/a/49075797/385273
Ben

62

Experimente isso.

Aqui está a parte do serviço.

[ServiceContract]
public interface IService
{
    [OperationContract]
    void  HelloWorld();
}

public class Service : IService
{
    public void HelloWorld()
    {
        //Hello World
    }
}

Aqui está o proxy

public class ServiceProxy : ClientBase<IService>
{
    public ServiceProxy()
        : base(new ServiceEndpoint(ContractDescription.GetContract(typeof(IService)),
            new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/MyAppNameThatNobodyElseWillUse/helloservice")))
    {

    }
    public void InvokeHelloWorld()
    {
        Channel.HelloWorld();
    }
}

E aqui está a parte de hospedagem de serviços.

var serviceHost = new ServiceHost
        (typeof(Service), new Uri[] { new Uri("net.pipe://localhost/MyAppNameThatNobodyElseWillUse") });
    serviceHost.AddServiceEndpoint(typeof(IService), new NetNamedPipeBinding(), "helloservice");
    serviceHost.Open();

    Console.WriteLine("Service started. Available in following endpoints");
    foreach (var serviceEndpoint in serviceHost.Description.Endpoints)
    {
        Console.WriteLine(serviceEndpoint.ListenUri.AbsoluteUri);
    }

Isso pode funcionar, mas não é tão flexível quanto apenas editar os arquivos app.config para o cliente e servidor ...
Alan S

9
Bom, já que expor os detalhes do aplicativo por meio de arquivos app.config muitas vezes não é desejado.
Frank Hileman

14
Este é um exemplo maravilhoso, no entanto, nunca use um endereço base de apenas net.pipe: // localhost /. Se você fizer isso e a máquina tiver qualquer outro programa que também use net.pipe: // localhost /, o ServiceHost lançará uma exceção quando você abri-lo. Em vez disso, use algo exclusivo como net.pipe: // localhost / MyAppNameThatNobodyElseWillUse. Espero que isso ajude alguém a economizar tempo e frustração!
Doug Clutter

Esta solução funciona bem. Particularmente para endpoints internos, onde não é necessário ter uma referência de serviço na configuração. Basta manter os contratos - simplesmente as definições de interface - em sua própria montagem e talvez o endereço na configuração. Não é tão provável que a ligação seja alterada.
Rob Von Nesselrode

2
Eu precisava adicionar /helloserviceao final do endereço do terminal no proxy.
Mormegil

14

Confira meu exemplo altamente simplificado do Echo : ele é projetado para usar comunicação HTTP básica, mas pode ser facilmente modificado para usar pipes nomeados editando os arquivos app.config para o cliente e servidor. Faça as seguintes alterações:

Edite o arquivo app.config do servidor , removendo ou comentando a entrada http baseAddress e adicionando uma nova entrada baseAddress para o canal nomeado (chamado net.pipe ). Além disso, se você não pretende usar HTTP para um protocolo de comunicação, verifique se o serviceMetadata e serviceDebug ou é comentado ou excluído:

<configuration>
    <system.serviceModel>
        <services>
            <service name="com.aschneider.examples.wcf.services.EchoService">
                <host>
                    <baseAddresses>
                        <add baseAddress="net.pipe://localhost/EchoService"/>
                    </baseAddresses>
                </host>
            </service>
        </services>
        <behaviors>
            <serviceBehaviors></serviceBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>

Edite o arquivo app.config do cliente para que basicHttpBinding seja comentada ou excluída e uma entrada netNamedPipeBinding seja adicionada. Você também precisará alterar a entrada do ponto final para usar o tubo:

<configuration>
    <system.serviceModel>
        <bindings>
            <netNamedPipeBinding>
                <binding name="NetNamedPipeBinding_IEchoService"/>
            </netNamedPipeBinding>
        </bindings>
        <client>
            <endpoint address              = "net.pipe://localhost/EchoService"
                      binding              = "netNamedPipeBinding"
                      bindingConfiguration = "NetNamedPipeBinding_IEchoService"
                      contract             = "EchoServiceReference.IEchoService"
                      name                 = "NetNamedPipeBinding_IEchoService"/>
        </client>
    </system.serviceModel>
</configuration>

O exemplo acima só será executado com canais nomeados, mas nada o impede de usar vários protocolos para executar seu serviço. AFAIK, você deve conseguir fazer com que um servidor execute um serviço usando pipes nomeados e HTTP (bem como outros protocolos).

Além disso, a vinculação no arquivo app.config do cliente é altamente simplificada. Existem muitos parâmetros diferentes que você pode ajustar, além de apenas especificar o baseAddress ...


5
Os links agora estão mortos.
Chris Weber

2

Criei este exemplo simples a partir de diferentes resultados de pesquisa na internet.

public static ServiceHost CreateServiceHost(Type serviceInterface, Type implementation)
{
  //Create base address
  string baseAddress = "net.pipe://localhost/MyService";

  ServiceHost serviceHost = new ServiceHost(implementation, new Uri(baseAddress));

  //Net named pipe
  NetNamedPipeBinding binding = new NetNamedPipeBinding { MaxReceivedMessageSize = 2147483647 };
  serviceHost.AddServiceEndpoint(serviceInterface, binding, baseAddress);

  //MEX - Meta data exchange
  ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
  serviceHost.Description.Behaviors.Add(behavior);
  serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexNamedPipeBinding(), baseAddress + "/mex/");

  return serviceHost;
}

Usando o URI acima, posso adicionar uma referência ao serviço da web em meu cliente.


-2

Achei este site muito útil, e o projeto de exemplo é executado sem nenhum ajuste: https://dotnet-experience.blogspot.com/2012/02/inter-process-duplex-communication-with.html

Não se esqueça de habilitar o suporte a Named Pipe nos Recursos do Windows. Este artigo tem algumas boas capturas de tela para esse efeito na resposta principal: WCF Named Pipe no Windows Service usando App.Config

O projeto referenciado na solução aceita não funciona como está no meu PC. Tentei algumas correções no app.config, mas ainda recebo a seguinte exceção:

System.InvalidOperationException: 'Service' WpfWcfNamedPipeBinding.NamedPipeBindingService 'tem zero pontos de extremidade de aplicativo (não infra-estrutura). Isso pode ser porque nenhum arquivo de configuração foi localizado para seu aplicativo, ou porque nenhum elemento de serviço correspondente ao nome do serviço pôde ser encontrado no arquivo de configuração, ou porque nenhum terminal foi definido no elemento de serviço. '

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.