我有一个托管WCF服务的应用。一些信息:
但是当我从客户端调用方法时,服务器没有得到调用。我看到了#34; Timeout异常"当" CallServer"方法被调用。
如果您建议更改InstanceContextMode
或ConcurrencyMode
或SessionMode
的设置,请先自行尝试,因为我已经尝试了这些组合但没有帮助。
这里的代码是一个示例,但可用于测试。要使用此代码,请在表单上创建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();
}
}
}
有关信息:修复是使用&#34; UseSynchronizationContext = false&#34;在ContractServer
中并禁用主机绑定中的端口共享。但我不知道为什么。
答案 0 :(得分:2)
你可能陷入僵局。
当您在应用程序中托管WCF
服务时,它会使用该应用程序的同步上下文。在这种情况下,WinForms
应用程序,单线程同步上下文。
所以当你的&#34;客户&#34;打电话给你的服务器&#34;它被阻止,直到它得到响应和&#34;服务器&#34;无法发送该响应,因为单个线程被&#34;客户端&#34;阻止,因此死锁。
要解决此问题,您需要告诉服务不要使用该同步上下文:
[ServiceBehavior(
UseSynchronizationContext = false,
InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple,
IncludeExceptionDetailInFaults = true)]
public class ContractServer : IContract
{
public void CallServer()
{
MessageBox.Show("Client called!");
}
}