簡體   English   中英

連接到在另一台計算機上作為 Windows 服務運行的 WCF

[英]Connecting to WCF running as a Windows Service on another computer

我有一個 WinForms 客戶端應用程序。 我將 WCF 服務器作為我編寫的 Windows 服務的一部分在另一台計算機上運行。 我首先嘗試了NetPipeBinding ,現在嘗試了NetTcpBinding 我確實在具有高級安全性的 Windows 防火牆中打開了 2 個端口。 服務器操作系統是Windows Server 2016

這是服務器代碼:

public Boolean CreatePipeServer(out string logEntry)
{
    try
    {
        NetTcpBinding ipcBinding = new NetTcpBinding()
        {
            Security = new NetTcpSecurity()
            {
                Mode = SecurityMode.None,
                Transport = new TcpTransportSecurity()
                {
                    ClientCredentialType = TcpClientCredentialType.None,
                    ProtectionLevel = System.Net.Security.ProtectionLevel.None,
                },
            },
            MaxBufferPoolSize = 6553600,
            MaxBufferSize = 6553600,
            MaxReceivedMessageSize = 6553600,
            MaxConnections = 1000,
            ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
            {
                MaxArrayLength = 2147483647,
                MaxBytesPerRead = 2147483647,
                MaxDepth = 2147483647,
                MaxNameTableCharCount = 2147483647,
                MaxStringContentLength = 2147483647,
            },
        };

        // Instantiate: Host Service
        Uri uriMex = new Uri("http://localhost:8000");
        this.ServiceParent.ServiceIpcAppToService.HostIpcAppToService = new ServiceHost(typeof(IpcAppToService), uriMex);

        // Instantiate: Endpoint
        Uri uriService = new Uri("net.tcp://localhost:8004/StampIpcAppToService");
        this.ServiceParent.ServiceIpcAppToService.HostIpcAppToService.AddServiceEndpoint(typeof(StampIpc.IIpcAppToService), ipcBinding, uriService);

        // Instantiate: Service Meta Behavior
        ServiceMetadataBehavior ipcSmb = this.ServiceParent.ServiceIpcAppToService.HostIpcAppToService.Description.Behaviors.Find<ServiceMetadataBehavior>();
        if (null == ipcSmb)
        {
            ipcSmb = new ServiceMetadataBehavior()
            {
                HttpGetEnabled = true,
            };
            this.ServiceParent.ServiceIpcAppToService.HostIpcAppToService.Description.Behaviors.Add(ipcSmb);
            ServiceDescription serviceDescription = this.ServiceParent.ServiceIpcAppToService.HostIpcAppToService.Description;
        }

        // Instantiate: MEX Biding
        Binding ipcMexBinding = MetadataExchangeBindings.CreateMexHttpBinding();
        this.ServiceParent.ServiceIpcAppToService.HostIpcAppToService.AddServiceEndpoint(typeof(IMetadataExchange), ipcMexBinding, "MEX");

        // Capture events.
        ...

        // Start the service.
        this.ServiceParent.ServiceIpcAppToService.HostIpcAppToService.Open();

        return true;
    }

    catch (Exception) { }

return false;
}

我試圖通過轉到Visual Studio 2019Add > Service Reference...來測試有效的通信鏈接。 無論我輸入什么,我都會不斷收到一種或另一種錯誤。 目前,我放置了:

net.tcp://10.10.70.134:8004/StampIpcAppToService

這會引發錯誤:

無法識別 URI 前綴。 元數據包含無法解析的引用:“net.tcp://10.10.70.134:8004/StampIpcAppToService”。 元數據包含無法解析的引用:“net.tcp://10.10.70.134:8004/StampIpcAppToService”。 如果在當前解決方案中定義了服務,請嘗試構建解決方案並再次添加服務引用。

我已經有了客戶端代碼,但是如果我不能讓Add Service Reference工作,那么客戶端代碼肯定不會工作。

上面的代碼作為Windows ServiceOnStart事件的一部分開始。

我究竟做錯了什么?

更新

答案解決了上面的直接問題,但是我的真實代碼使用了類似於服務器端的代碼,我收到了一個錯誤。 我根據答案和一些調試修改了代碼。 當前代碼是:

    public static Boolean ConnectToService()
    {
        ComAppToService.IsPipeAppToService = false;
        ComAppToService.IpcPipeFactory = null;
        Program.HostIpcAppToService = null;
        try
        {
            // Instantiate: Callack
            var ipcCallback = new IpcAppToServiceBack();
            InstanceContext ipcCallbackInstance = new InstanceContext(ipcCallback);

            // Instantiate: Endpoint
            Uri ipcUri = new Uri($"http://10.10.70.134:8000/mex");
            EndpointAddress ipcEndpoint = new EndpointAddress(ipcUri);

            // Instantiate: Binding
            // https://stackoverflow.com/questions/464707/maximum-array-length-quota
            WSDualHttpBinding ipcBindingHttp = new WSDualHttpBinding()
            {
                Security = new WSDualHttpSecurity() { Mode = WSDualHttpSecurityMode.None },
                MaxBufferPoolSize = 6553600,
                MaxReceivedMessageSize = 6553600,
                ClientBaseAddress = ipcUri,
                ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
                {
                    MaxArrayLength = 2147483647,
                    MaxBytesPerRead = 2147483647,
                    MaxDepth = 2147483647,
                    MaxNameTableCharCount = 2147483647,
                    MaxStringContentLength = 2147483647,
                },
            };

            // Instantiate: Factory
            ComAppToService.IpcPipeFactory = new DuplexChannelFactory<IIpcAppToService>(ipcCallbackInstance, ipcBindingHttp, ipcEndpoint);
            Program.HostIpcAppToService = ComAppToService.IpcPipeFactory.CreateChannel();

            // Open: Callback
            Program.HostIpcAppToService.OpenCallback(IpcCallbackDest.App);
            ComAppToService.IsPipeAppToService = true;

            return true;
        }

        catch (Exception ex)
        {
            // Log the exception.
            Debug.WriteLine(ex.Message);
        }

        return false;
    }

例外:

InnerException = {"由於 EndpointDispatcher 的 ContractFilter 不匹配,無法在接收方處理帶有 Action ' http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence ' 的消息。這可能是因為要么是合同不匹配(不匹配的操作之間...

更新 2(反映更新的答案)

使用NetTcpBinding產生此錯誤:

使用 URI:

Uri ipcUri = new Uri($"net.tcp://10.10.70.134:8004");

生成

Message = "There was no endpoint listening at net.tcp://jmr-engineering:8004/ that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details."

使用 URI:

Uri ipcUri = new Uri($"net.tcp://10.10.70.134:8000");

生成

Message = "You have tried to create a channel to a service that does not support .Net Framing. It is possible that you are encountering an HTTP endpoint."

InnerException = {"Expected record type 'PreambleAck', found '72'."}

答案:

接受的答案需要修改。 Abraham 沒有正確的URI ,但是他將我指向SvcUtil.exe ,它給了我。

網址:

net.tcp://10.10.70.134:8004/StampIpcAppToService

我確實需要NetTcpBinding ,所以最終的客戶端代碼是:

    /// <summary>
    /// Connects the ipc application to service.
    /// </summary>
    /// <returns>Boolean.</returns>
    public static Boolean ConnectToService()
    {
        ComAppToService.IsPipeAppToService = false;
        ComAppToService.IpcPipeFactory = null;
        Program.HostIpcAppToService = null;
        try
        {
            // Instantiate: Callack
            var ipcCallback = new IpcAppToServiceBack();
            InstanceContext ipcCallbackInstance = new InstanceContext(ipcCallback);

            // Instantiate: Endpoint
            Uri ipcUri = new Uri($"net.tcp://10.10.70.134:8004/StampIpcAppToService");
            EndpointAddress ipcEndpoint = new EndpointAddress(ipcUri);

            // Instantiate: Binding
            // https://stackoverflow.com/questions/464707/maximum-array-length-quota
            NetTcpBinding ipcBindingHttp = new NetTcpBinding()
            {
                Security = new NetTcpSecurity() { Mode = SecurityMode.None },
                MaxBufferPoolSize = 6553600,
                MaxReceivedMessageSize = 6553600,
                MaxBufferSize = 6553600,
                MaxConnections = 1000,
                ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
                {
                    MaxArrayLength = 2147483647,
                    MaxBytesPerRead = 2147483647,
                    MaxDepth = 2147483647,
                    MaxNameTableCharCount = 2147483647,
                    MaxStringContentLength = 2147483647,
                },
            };

            // Instantiate: Factory
            ComAppToService.IpcPipeFactory = new DuplexChannelFactory<IIpcAppToService>(ipcCallbackInstance, ipcBindingHttp, ipcEndpoint);
            Program.HostIpcAppToService = ComAppToService.IpcPipeFactory.CreateChannel();

            // Open: Callback
            Program.HostIpcAppToService.OpenCallback(IpcCallbackDest.App);
            ComAppToService.IsPipeAppToService = true;

            return true;
        }

        catch (Exception ex)
        {
            // Log the exception.
            Debug.WriteLine(ex.Message);
        }

        return false;
    }

這是output.configSvcUtil.exe的輸出。 IpcAppToService.cs文件沒用,但配置文件絕對有用。

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <system.serviceModel>
        <bindings>
            <netTcpBinding>
            <binding name="NetTcpBinding_IIpcAppToService">
                <security mode="None" />
            </binding>
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://localhost:8004/StampIpcAppToService"
            binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IIpcAppToService"
            contract="IIpcAppToService" name="NetTcpBinding_IIpcAppToService" />
        </client>
        </system.serviceModel>
    </configuration>

添加服務引用依賴於服務元數據地址而不是服務地址。 根據您的上述設置,添加服務引用對話框中的 Uri 應該是,

http://10.10.70.134:8000/mex

通常,我們必須通過添加Mex端點或通過ServiceMetedataBehaviorHttpGetEnabled屬性來公開元數據。 隨后,客戶端可以使用SVCUtil工具生成客戶端代理。
https://docs.microsoft.com/en-us/dotnet/framework/wcf/accessing-services-using-a-wcf-client
Visual StudioAdding Service reference對話框是生成客戶端代理的快捷方式。 它依賴於Mex服務端點。 快捷方式需要Mex端點地址。
如果有什么我可以幫忙的,請隨時告訴我。
更新。
雙工通信意味着我們應該在客戶端使用Nettcpbinding (支持雙工)。

class Program
    {
        static void Main(string[] args)
        {
            NetTcpBinding binding = new NetTcpBinding()
            {
                Security = new NetTcpSecurity
                {
                    Mode = SecurityMode.None
                },
                MaxBufferPoolSize = 6553600,
                MaxBufferSize = 6553600,
                MaxReceivedMessageSize = 6553600,
                MaxConnections = 1000,
                ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
                {
                    MaxArrayLength = 2147483647,
                    MaxBytesPerRead = 2147483647,
                    MaxDepth = 2147483647,
                    MaxNameTableCharCount = 2147483647,
                    MaxStringContentLength = 2147483647,
                },
            };
            //replace it with your practical service address.
            Uri uri = new Uri("net.tcp://10.157.13.69:8004");
            ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, new EndpointAddress(uri));
            IService service = factory.CreateChannel();
            var result = service.Test();
            Console.WriteLine(result);

        }

    }

    //the service contract shared between the client-side and the server-side.
    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        string Test();

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM