c# - 当客户端连接到 WCF 服务时观察超时异常 - 两者都驻留在同一应用程序中

标签 c# .net wcf

我有一个托管 WCF 服务的应用程序。一些信息:

  • 它必须是一个单例应用程序 - 意味着它的另一个实例不能并行运行。现在,假设以下示例表单应用程序已按此设计。
  • 它也需要充当客户端。
  • 它使用 net.tcp 绑定(bind)
  • 它使用 SecurityMode = Transport

但是当我从客户端调用方法时,服务器没有得到调用。当调用“CallServer”方法时,我看到“超时异常”。

如果您建议更改 InstanceContextModeConcurrencyModeSessionMode 的设置,请先自行尝试,因为我已经尝试过这些组合他们没有提供帮助。

这里的代码是一个示例,但可以用来测试。要使用此代码,请在表单上创建 2 个按钮:btnHostService 和 btnClientInvoke。

using System;
using System.ServiceModel;
using System.Windows.Forms;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        ServiceHost _host;
        const string URI = "net.tcp://localhost:8602/MyService";

        public Form1() {
            InitializeComponent();
            this.FormClosing += delegate { if (_host != null) _host.Close(new TimeSpan(0, 1, 0)); };
        }

        private void btnHostService_Click(object sender, EventArgs e) {
            //don't host again
            if (_host != null) return;

            _host = new ServiceHost(typeof(ContractServer), new Uri(URI));

            var binding = new NetTcpBinding(SecurityMode.Transport) { PortSharingEnabled = true };
            binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;

            _host.AddServiceEndpoint(typeof(IContract), binding, string.Empty);
            _host.Opened += delegate { MessageBox.Show(this, "Service Hosted"); };
            _host.Open();
        }

        private void btnClientInvoke_Click(object sender, EventArgs e) {
            var binding = new NetTcpBinding(SecurityMode.Transport) { PortSharingEnabled = true };
            binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;

            ////set all of them to 1 min - which is default
            //binding.OpenTimeout = new TimeSpan(0, 1, 0);
            //binding.SendTimeout = new TimeSpan(0, 1, 0);
            //binding.CloseTimeout = new TimeSpan(0, 1, 0);

            ContractClient client = null;
            try {
                client = new ContractClient(binding, new EndpointAddress(URI));
                client.CallServer();
            }
            catch (Exception exc) {
                MessageBox.Show(exc.ToString());
            }

            if (client != null) {
                try {
                    client.Close();
                }
                catch (Exception exc) {
                    MessageBox.Show(exc.ToString());
                    client.Abort();
                }
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
            if (_host != null)
                _host.Close(new TimeSpan(0, 1, 0));
        }
    }

    [ServiceContract(SessionMode = SessionMode.Allowed)]
    public interface IContract {
        [OperationContract(IsOneWay = true)]
        void CallServer();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, IncludeExceptionDetailInFaults = true)]
    public class ContractServer : IContract {
        public void CallServer() {
            MessageBox.Show("Client called!");
        }
    }
    public class ContractClient : System.ServiceModel.ClientBase<IContract>, IContract {
        public ContractClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { }

        public void CallServer() {
            base.Channel.CallServer();
        }
    }
}

更新 1

信息:修复方法是在 ContractServer 中使用“UseSynchronizationContext = false”并在主机绑定(bind)中禁用端口共享。但不知道为什么。

最佳答案

您可能遇到了僵局。

当您在应用程序中托管 WCF 服务时,它会使用该应用程序的同步上下文。在本例中,是一个 WinForms 应用程序,一个单线程同步上下文。

因此,当您的“客户端”调用您的“服务器”时,它会被阻塞,直到获得响应,并且“服务器”无法发送该响应,因为单个线程被“客户端”阻塞,因此死锁。

要解决此问题,您需要告诉服务不要使用该同步上下文:

[ServiceBehavior(
    UseSynchronizationContext = false,
    InstanceContextMode = InstanceContextMode.Single, 
    ConcurrencyMode = ConcurrencyMode.Multiple, 
    IncludeExceptionDetailInFaults = true)]
public class ContractServer : IContract 
{
    public void CallServer() 
    {
        MessageBox.Show("Client called!");
    }
}

关于c# - 当客户端连接到 WCF 服务时观察超时异常 - 两者都驻留在同一应用程序中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23760243/

相关文章:

c# - C# 如何让文本显示在按钮上?

c# - 方法是否选择退出类级别的 AuthorizeAttribute?

c# - 自托管 Wcf 服务于 wsdl 但在调用时为 404

c# - 如何从 javaScript 使用 wcf webservice

c# - BackgroundWorker _ AppDomain.UnhandledException 未捕获异常

c# - 在运行时动态更改 Win8 XAML 应用程序中的 ThemeResource/StaticResource 或其他?

c# - 任务如何知道它何时完成?

c# - 使用 Entity Framework 4.0 中的上下文确定实体的主键

.net - WCF 自定义绑定(bind) - 服务不支持的内容类型

c# - Mono.Cecil 是否负责分支机构等位置?