Przykład minimalnego potoku nazwanego WCF


90

Szukam minimalnego przykładu potoków nazwanych WCF (oczekuję dwóch minimalnych aplikacji, serwera i klienta, które mogą komunikować się za pośrednictwem nazwanego potoku).

Firma Microsoft ma genialny artykuł samouczek wprowadzający, który opisuje WCF za pośrednictwem protokołu HTTP, i szukam czegoś podobnego na temat WCF i nazwanych potoków.

Znalazłem kilka postów w Internecie, ale są one trochę „zaawansowane”. Potrzebuję czegoś minimalnego, tylko obowiązkowej funkcjonalności, abym mógł dodać swój kod i uruchomić aplikację.

Jak to zmienić, aby użyć nazwanego potoku?

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

Jak to zmienić, aby użyć nazwanego potoku?

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

Jak wygenerować klienta, aby używał nazwanego potoku?


Odpowiedzi:


80

Właśnie znalazłem ten doskonały mały tutorial . uszkodzony link ( wersja w pamięci podręcznej )

Postępowałem również zgodnie z tutorialem Microsoftu, który jest fajny, ale potrzebowałem też tylko rur.

Jak widać, nie potrzebujesz plików konfiguracyjnych i tych wszystkich bałaganu.

Nawiasem mówiąc, używa zarówno protokołu HTTP, jak i potoków. Po prostu usuń wszystkie linie kodu związane z HTTP, a otrzymasz przykład czystego potoku.


2
Dzięki! Ponadto, próbując zbudować usługę, która używa pliku web.config do swojej konfiguracji zamiast konfiguracji zakodowanej na stałe, zobacz ten przykład firmy Microsoft: msdn.microsoft.com/en-us/library/ms752253.aspx
Nullius

3
Link nie działa, czy samouczek jest gdzie indziej?
user1069816

Po prostu spędziłem chwilę, próbując dowiedzieć się, dlaczego „rura została zakończona”. Oto moje rozwiązanie na ten temat, mam nadzieję, że pomoże: stackoverflow.com/a/49075797/385273
Ben

62

Spróbuj tego.

Oto część serwisowa.

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

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

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

A oto część dotycząca hostingu usług.

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

To może działać, ale nie jest tak elastyczne, jak zwykła edycja plików app.config dla klienta i serwera ...
Alan S,

9
Fajnie, ponieważ ujawnianie szczegółów aplikacji za pośrednictwem plików app.config często nie jest pożądane.
Frank Hileman,

14
To wspaniały przykład, jednak nigdy nie używaj adresu bazowego po prostu net.pipe: // localhost /. Jeśli to zrobisz, a maszyna ma inny program, który również używa net.pipe: // localhost /, ServiceHost zgłosi wyjątek po otwarciu. Zamiast tego użyj czegoś unikalnego, takiego jak net.pipe: // localhost / MyAppNameThatNobodyElseWillUse. Mam nadzieję, że pomoże to komuś zaoszczędzić trochę czasu i frustracji!
Doug Clutter

To rozwiązanie działa dobrze. Szczególnie w przypadku wewnętrznych punktów końcowych, w których odwołanie do usługi w konfiguracji nie jest konieczne. Po prostu zachowaj kontrakty - po prostu definicje interfejsów - w ich własnym zestawie i być może adres w config. Jest mało prawdopodobne, że oprawa się zmieni.
Rob Von Nesselrode

2
Musiałem dodać /helloservicena końcu adresu punktu końcowego w proxy.
Mormegil

14

Sprawdź mój bardzo uproszczony przykład Echo : jest przeznaczony do korzystania z podstawowej komunikacji HTTP, ale można go łatwo zmodyfikować, aby używał nazwanych potoków, edytując pliki app.config dla klienta i serwera. Wprowadź następujące zmiany:

Edytuj plik app.config serwera , usuwając lub komentując wpis http baseAddress i dodając nowy wpis baseAddress dla nazwanego potoku (o nazwie net.pipe ). Ponadto, jeśli nie zamierzasz używać HTTP jako protokołu komunikacyjnego, upewnij się, że serviceMetadata i serviceDebug są wykomentowane lub usunięte:

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

Edytuj plik app.config klienta, tak aby element basicHttpBinding został wykomentowany lub usunięty oraz dodano wpis netNamedPipeBinding . Będziesz także musiał zmienić wpis punktu końcowego, aby użyć potoku:

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

Powyższy przykład będzie działał tylko z nazwanymi potokami, ale nic nie powstrzymuje Cię przed użyciem wielu protokołów do uruchomienia usługi. AFAIK, powinieneś być w stanie sprawić, by serwer uruchamiał usługę przy użyciu zarówno nazwanych potoków, jak i protokołu HTTP (a także innych protokołów).

Ponadto powiązanie w pliku app.config klienta jest znacznie uproszczone. Istnieje wiele różnych parametrów, które można dostosować, poza zwykłym określeniem adresu baseAddress ...


5
Linki są teraz martwe.
Chris Weber,

2

Stworzyłem ten prosty przykład na podstawie różnych wyników wyszukiwania w Internecie.

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

Korzystając z powyższego URI, mogę dodać odniesienie w moim kliencie do usługi internetowej.


-2

Uważam, że ta witryna jest naprawdę pomocna, a przykładowy projekt działa bez żadnych zmian: https://dotnet-experience.blogspot.com/2012/02/inter-process-duplex-communication-with.html

Nie zapomnij włączyć obsługi potoku nazwanego w funkcjach systemu Windows. W tym artykule znajdują się dobre zrzuty ekranu przedstawiające ten efekt w pierwszej odpowiedzi: potok nazwany WCF w usłudze Windows przy użyciu aplikacji.

Projekt, do którego odwołuje się zaakceptowane rozwiązanie, nie działa tak, jak jest na moim komputerze. Wypróbowałem kilka poprawek w pliku app.config, ale nadal otrzymuję następujący wyjątek:

System.InvalidOperationException: „Usługa” WpfWcfNamedPipeBinding.NamedPipeBindingService ”ma zero punktów końcowych aplikacji (niezwiązanych z infrastrukturą). Może to być spowodowane tym, że nie znaleziono pliku konfiguracyjnego dla twojej aplikacji, nie można znaleźć elementu usługi pasującego do nazwy usługi w pliku konfiguracyjnym lub ponieważ w elemencie usługi nie zdefiniowano żadnych punktów końcowych. '

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.