Именованный канал WCF в службе Windows с использованием App.Config

#c# #wcf #app-config #named-pipes

#c# #wcf #app-config #именованные каналы

Вопрос:

Я разочарован. Хорошо, вот ошибка.

В net.pipe не было прослушиваемой конечной точки://localhost/MyIpcAppToService, которая могла бы принять сообщение. Это часто вызвано неправильным адресом или действием SOAP. Смотрите InnerException, если оно присутствует, для получения более подробной информации.

Я наконец-то заработал файл App.Config, по крайней мере, жалоб нет.

Текущее приложение.Config

 <?xml version="1.0" encoding="utf-8"?>
<configuration>
    <!-- When deploying the service library project, the content of the config file must be added to the host's 
  app.config file. System.Configuration does not support config files for libraries. -->
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
    </startup>
    <system.serviceModel>
        <services>
            <service behaviorConfiguration="MyServiceBehavior" name="MyService.Communication.IpcAppToService">
                <endpoint address="net.pipe://localhost/MyIpcAppToService" binding="wsDualHttpBinding" bindingConfiguration="MyAppToServiceEndpointBinding" contract="MyIpc.IIpcAppToService"/>
                <endpoint address="mex" binding="mexHttpBinding" name="mex" contract="IMetadataExchange"/>
                <host>
                    <baseAddresses>
                        <add baseAddress="http://localhost:8733/MyService/"/>
                    </baseAddresses>
                </host>
            </service>
  </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="MyServiceBehavior">
                    <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
                    <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment  to avoid disclosing exception information -->
                    <serviceDebug includeExceptionDetailInFaults="true"/>
                    <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <protocolMapping>
            <add scheme="http" binding="wsHttpBinding" bindingConfiguration="MyAppToServiceEndpointBinding" />
        </protocolMapping>
        <bindings>
            <wsDualHttpBinding>
                <!-- https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/wshttpbinding -->
                <binding name="MyAppToServiceEndpointBinding"
                                 transactionFlow="true"
                                 sendTimeout="00:01:00"
                                 maxReceivedMessageSize="2147483647"
                                 messageEncoding="Mtom">
                </binding>
            </wsDualHttpBinding>
        </bindings>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true">
            <baseAddressPrefixFilters>
                <add prefix="http://localhost:8733"/>
            </baseAddressPrefixFilters>
        </serviceHostingEnvironment>
    </system.serviceModel>
    <appSettings>
        <add key="countoffiles" value="7"/>
        <add key="logfilelocation" value="abc.txt"/>
    </appSettings>
</configuration>
  

Раньше у меня был:

 <endpoint address="http://localhost:8733/MyIpcAppToService" ...
  

и в событии службы Windows OnStart() :

(начиная с этого вопроса, следующий код теперь закомментирован, поскольку App.config файл должен запускать named.pipe.)

 public Boolean CreatePipeServer()
{
    string eventText = $"My Service: CommAppToService::CreatePipeServer(IPC App to Service){Environment.NewLine}";
    try
    {
        if (null != this.ServiceParent.HostIpcAppToService)
            this.ServiceParent.HostIpcAppToService = null;

        string pipeBaseAddress = @"net.pipe://localhost/MyIpcAppToService";
        this.ServiceParent.HostIpcAppToService = new ServiceHost(typeof(IpcAppToService), new Uri(pipeBaseAddress));
        NetNamedPipeBinding pipeBinding = new NetNamedPipeBinding()
        {
            //ReceiveTimeout = new TimeSpan(0, 0, 0, 0, Constants.My_TimeoutMsSendReceive),
            //SendTimeout = new TimeSpan(0, 0, 0, 0, Constants.My_TimeoutMsSendReceive),
        };
        this.ServiceParent.HostIpcAppToService.AddServiceEndpoint(typeof(IIpcAppToService), pipeBinding, "MyIpcAppToService");
        this.ServiceParent.HostIpcAppToService.UnknownMessageReceived  = HostIpcAppServer_UnknownMessageReceived;
        this.ServiceParent.HostIpcAppToService.Faulted  = HostIpcAppServer_Faulted;
        this.ServiceParent.HostIpcAppToService.Closing  = HostIpcAppServer_Closing;
        this.ServiceParent.HostIpcAppToService.Closed  = HostIpcAppServer_Closed;

        this.IpcAppToService = new IpcAppToService();
        this.IpcAppToService.ApplyDispatchBehavior(this.ServiceParent.HostIpcAppToService);
        this.IpcAppToService.Validate(this.ServiceParent.HostIpcAppToService);
        this.ServiceParent.HostIpcAppToService.Open();

        return true;
    }
  

Я читал, что служба автоматически запустит службы, размещенные в App.Config файле, на самом деле в MyExeName.exe.config файле. Я продолжал просматривать код и увидел, что он почти идентичен, поэтому я заменил http:// на net.pipe:// .

Sadly, old code, new code, in between code, all nothing. I keep receiving the same error.

I use the following to connect to the service from my desktop application.

 public static Boolean ConnectToService()
{
    try
    {
        var callback = new IpcCallbackAppToService();
        var context = new InstanceContext(callback);
        var pipeFactory = new DuplexChannelFactory<IIpcAppToService>(context, new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/MyIpcAppToService"));
        Program.HostIpcAppToService = pipeFactory.CreateChannel();
        Program.HostIpcAppToService.Connect();
        CommAppToService.IsPipeAppToService = true;

        return true;
    }

    catch (Exception ex)
    {
        // Log the exception.
        Errors.LogException(ex);
    }

    return false;
}
  

For whatever it is worth, here is:

Interface

 [ServiceContract(SessionMode = SessionMode.Allowed, CallbackContract = typeof(IIpcCallbackAppToService))]
public interface IIpcAppToService
{
    [OperationContract(IsOneWay = false)]
    [FaultContractAttribute(typeof(IpcAppToServiceFault))]
    UInt16 GetServiceId();

    ...
}
  

Service:

 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class IpcAppToService : IIpcAppToService, IErrorHandler
{
    public static IIpcCallbackAppToService Callback { get; set; } = null;

    public void OpenCallback()
    {
        IpcAppToService.Callback = OperationContext.Current.GetCallbackChannel<IIpcCallbackAppToService>();
    }

    public void CloseCallback()
    {
        IpcAppToService.Callback = null;
    }

    public void SendMessage(string message)
    {
        //MessageBox.Show(message);
    }

    public UInt16 GetServiceId()
    {
        return Constants.My_Id_AppToService;
    }

    ...
}
  

Inner Exception from my desktop WinForms Application
(Note, there were no further inner exceptions than this one.):

«The pipe endpoint ‘net.pipe://localhost/MyIpcAppToService’ could not be found on your local machine.»

Why do I keep seeing this error?

UPDATE AFTER 1ST ANSWER

The direction that I would like to take is opposite of the answer, yet the same, namely that the service starts with the App.config and the client uses C# code.

Sadly, I still get the same error.

Revised Server Side App.config

 <?xml version="1.0" encoding="utf-8"?>
<configuration>
    <!-- When deploying the service library project, the content of the config file must be added to the host's 
  app.config file. System.Configuration does not support config files for libraries. -->
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
    </startup>
    <system.serviceModel>
        <services>
            <service behaviorConfiguration="BehaviorMyService" name="MyService.Communication.IpcAppToService">
                <endpoint address="net.pipe://localhost/MyIpcAppToService"
                                    binding="netNamedPipeBinding"
                                    bindingConfiguration="EndpointBindingMyAppToService"
                                    contract="MyIpc.IIpcAppToService"
                                    />
                <endpoint address="mex" binding="mexHttpBinding" name="mex" contract="IMetadataExchange"/>
                <host>
                    <baseAddresses>
                        <add baseAddress="http://localhost:8733/MyService/"/>
                    </baseAddresses>
                </host>
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="BehaviorMyService">
                    <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
                    <serviceMetadata httpGetEnabled="true"
                                                     httpsGetEnabled="true"
                                                     />
                    <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment  to avoid disclosing exception information -->
                    <serviceDebug includeExceptionDetailInFaults="true"/>
                    <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <bindings>
            <netNamedPipeBinding>
                <!-- https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/wshttpbinding -->
                <binding name="EndpointBindingMyAppToService"
                                 closeTimeout="00:01:00"  
                                 openTimeout="00:01:00"   
                                 receiveTimeout="00:10:00"   
                                 sendTimeout="00:01:00"  
                                 transactionFlow="false"   
                                 transferMode="Buffered"   
                                 transactionProtocol="OleTransactions"  
                                 hostNameComparisonMode="StrongWildcard"   
                                 maxBufferPoolSize="524288"  
                                 maxBufferSize="65536"   
                                 maxConnections="10"   
                                 maxReceivedMessageSize="2147483647"
                                 >
                    <security mode="None">
                        <transport protectionLevel="None" />
                    </security>
                </binding>
            </netNamedPipeBinding>
        </bindings>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true">
            <baseAddressPrefixFilters>
                <add prefix="http://localhost:8733"/>
            </baseAddressPrefixFilters>
        </serviceHostingEnvironment>
    </system.serviceModel>
    <appSettings>
        <add key="countoffiles" value="7"/>
        <add key="logfilelocation" value="abc.txt"/>
    </appSettings>
</configuration>
  

Пересмотренный код C # на стороне клиента:

 var callback = new IpcCallbackAppToService();
InstanceContext context = new InstanceContext(callback);
NetNamedPipeBinding binding = new NetNamedPipeBinding();
binding.Security.Mode = NetNamedPipeSecurityMode.None;
EndpointAddress endpointAddress = new EndpointAddress("net.pipe://localhost/MyIpcAppToService");
var pipeFactory = new DuplexChannelFactory<IIpcAppToService>(context, binding, endpointAddress);
Program.HostIpcAppToService = pipeFactory.CreateChannel();
Program.HostIpcAppToService.Connect();
CommAppToService.IsPipeAppToService = true;
  

Служба не выдает исключений, которые я могу обнаружить, поскольку EventViewer чист, только сообщение об успешном завершении OnStart (). Я знаю, что система обрабатывает App.config файл, так как ранее, когда у меня были ошибки, Windows Event Viewer продолжал жаловаться, но не больше.

Вот некоторые документы Microsoft, которые я использовал:

Привязка NetNamedPipeBinding

netNamedPipeBinding2

Я пробовал IO Ninja, но указав \.pipeMyIpcToService for File Stream , Pipe Listener и Pipe Monitor , но там ничего не отображается, даже когда я пытаюсь подключиться с помощью моего настольного приложения WinForms, которое затем выдает исключение no pipe listener found.

В чем может быть проблема?

Комментарии:

1. Итак, существует ли InnerException?

2. @stuartd В данном случае был, но там говорилось то же самое: «Не удалось найти конечную точку канала ‘net.pipe://localhost/MyIpcAppToService’ на вашем локальном компьютере».

3. Щелчок правой кнопкой мыши по моему клиентскому приложению и выбор Add> Добавить ссылку на службу и вставка «net.pipe://localhost /MyIpcAppToService / mex» выдает то же сообщение, подразумевающее проблему на стороне сервера.

Ответ №1:

 <endpoint address="net.pipe://localhost/MyIpcAppToService" binding="wsDualHttpBinding" bindingConfiguration="MyAppToServiceEndpointBinding" contract="MyIpc.IIpcAppToService"/>
  

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

  • TCP (net.tcp://localhost:8000/myservice) NetTcpBinding
  • IPC(net.pipe://localhost/mypipe) Привязка NetNamedPipeBinding
  • Http / Https(http://localhost:8000/myservice )
    Wshttpbinding,Wsdualhttpbinding,basichttpbinding

  • WebSocket(ws://localhost:3434) Nethttpbinding

  • MSMQ(net.msmq://localhost/ private/myservice) Привязка NETMSMQ

предполагается, что мы должны использовать привязку NetNamedPipeBinding для адреса службы. Пожалуйста, обратитесь к моему примеру.


Обновлено
У меня есть служба wcf, использующая привязку NetNamedPipeBinding, размещенную в IIS, хотелось бы, чтобы она была вам полезна.
Сервер (приложение-служба wcf)

     [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetData(int value);
}
    public class Service1 : IService1
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }
}
  

Web.config (на стороне сервера)

 <system.serviceModel>
    <services>
      <service behaviorConfiguration="BehaviorMyService" name="WcfService1.Service1">
        <endpoint address="MyIpcAppToService"
                            binding="netNamedPipeBinding"
                            bindingConfiguration="EndpointBindingMyAppToService"
                            contract="WcfService1.IService1"
                                    />
        <endpoint address="mex" binding="mexHttpBinding" name="mex" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="BehaviorMyService">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netNamedPipeBinding>
        <binding name="EndpointBindingMyAppToService"
                         closeTimeout="00:01:00"
                         openTimeout="00:01:00"
                         receiveTimeout="00:10:00"
                         sendTimeout="00:01:00"
                         transactionFlow="false"
                         transferMode="Buffered"
                         transactionProtocol="OleTransactions"
                         hostNameComparisonMode="StrongWildcard"
                         maxBufferPoolSize="524288"
                         maxConnections="10"
                         maxReceivedMessageSize="2147483647"
                                 >
          <security mode="None">
            <transport protectionLevel="None" />
          </security>
        </binding>
      </netNamedPipeBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true">
    </serviceHostingEnvironment>
  </system.serviceModel>
  

Включите новую функцию WCF.
введите описание изображения здесь
введите описание изображения здесь
Сайт IIS (включить net.pipe)
введите описание изображения здесь
введите описание изображения здесь
Клиент (консольное приложение)

   ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
    var result = client.GetData(34);
    Console.WriteLine(result);
  

Клиентское приложение.config (автоматически генерируется)
Я использую http-адрес (метаданные службы ПОЛУЧАЮТ адресhttp://localhost:8733/Service1.svc?wsdl ) для создания конфигурации.

   <system.serviceModel>
        <bindings>
            <netNamedPipeBinding>
                <binding name="NetNamedPipeBinding_IService1">
                    <security mode="None" />
                </binding>
            </netNamedPipeBinding>
        </bindings>
        <client>
            <endpoint address="net.pipe://mynetpipe/Service1.svc/MyIpcAppToService"
                binding="netNamedPipeBinding" bindingConfiguration="NetNamedPipeBinding_IService1"
                contract="ServiceReference1.IService1" name="NetNamedPipeBinding_IService1" />
        </client>
    </system.serviceModel>
  

Не стесняйтесь, дайте мне знать, если я могу чем-нибудь помочь.

Комментарии:

1. Я реализовал то, что вы предложили, см. Мой обновленный вопрос, только наоборот, а именно App.config для серверной части и C # для клиентской части. Я все еще получаю ту же ошибку. IO Ninja, не то чтобы я был экспертом в этом инструменте, не помогает в отладке.

2. Я закомментировал службу из App.config на сервере и добавил в код C #. Я сохранил код C # на клиенте и получил ту же ошибку. Что интересно, так это вторая часть «прослушивания конечной точки нет», которая «могла бы принять сообщение». Это может означать проблему на стороне клиента, а на стороне сервера все в порядке. Я проведу расследование.

3. На мой взгляд, что-то не так с публикацией службы через NetPIPE. Я обновил свой ответ, изменив свой пример, желаю, чтобы он был вам полезен.

4. Я заставил службу работать без дополнительных скриншотов, хотя мне пришлось использовать C # на сервере Windows, а не на App.config . Я не смог заставить службу работать с файлом конфигурации. Теперь, когда я пишу, возможно, мне нужно было создать файл .SVC, а не только 4 файла C #. Это работает. Спасибо! Дополнительная информация носит информативный характер.