通过WPF自托管连接时,带有net.tcp服务的WCF超时

时间:2012-06-22 13:51:42

标签: wpf wcf

我希望从托管它的同一个.exe中连接到WCF服务。我在WPF应用程序中托管服务:

        ServiceHost svc = new ServiceHost(typeof("Namespace.Service"));
        svc.Open();

的配置文件
  <service name="Namespace.Service" >
    <endpoint address="Contract/tcp"
              binding="netTcpBinding"
              contract="Namespace.IContract"/>
    <host>
      <baseAddresses>
        <add baseAddress="net.tcp://localhost:9002"/>
      </baseAddresses>
    </host>
  </service>

这允许我启动一个单独的VS实例,创建一个控制台应用程序并成功执行以下操作:

        IChannelFactory<IContract> facContract = new ChannelFactory<IContract>(new NetTcpBinding());
        IContract contract = facContract.CreateChannel(new EndpointAddress("net.tcp://localhost:9002/Contract/tcp"));

        string x = contract.GetProperty; //returns value I would expect

但是,如果我将原始WPF ServiceHost代码修改为以下内容,则在访问服务时会引发超时异常(注意:如果我在Console App Service主机中执行相同操作,则不会出现超时。 ..):

        ServiceHost svc = new ServiceHost(typeof("Namespace.Service"));
        svc.Open();

        IChannelFactory<IContract> facContract = new ChannelFactory<IContract>(new NetTcpBinding());
        IContract contract = facContract.CreateChannel(new EndpointAddress("net.tcp://localhost:9002/Contract/tcp"));

        string x = contract.GetProperty; //<-!!WCF Timeout exception thrown..

WCF跟踪不提供add'l详细信息(只是确认引发了超时异常)。有什么想法吗? {这不是关于WCF异常管理最佳实践的问题;我正在寻求从服务主机和服务主机内部访问服务。被这个好奇的超时异常阻止}

编辑: 当服务主机是WPF应用程序(可能是其他人)时,会发生此超时;但控制台应用程序作为服务主机的行为与我期望的一样(例如,可以访问自托管服务)。我已经更新了标题和标签以反映这个新信息...

提前致谢, Ť

2 个答案:

答案 0 :(得分:1)

这是因为WPF servicehost在与使用服务相同的线程上托管服务。问题在此处定义:http://social.msdn.microsoft.com/Forums/en/wcf/thread/74bc9d15-c458-4f1f-81a0-ebded46b68c4。此处详细说明了解决方案:http://msdn.microsoft.com/en-us/library/ms752260.aspx

解决方案是在单独的线程ala上启动服务主机端点

    private void StartHostThread()
    {
        // Before opening host, add endpoints...
        host.AddServiceEndpoint(typeof(IContract)),
                                new NetTcpBinding(), 
                                "Contract/tcp"); //Assumes base address of net.tcp://localhost:9002/

        //For hosting on its own thread, be sure to mark service attribute 
        //  as UseSyncContext == false
        ServiceBehaviorAttribute behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
        behavior.UseSynchronizationContext = false; 

        host.Open();
    }

一旦主机在线程上打开,那么就可以在主UI线程ala上使用服务了:

        EndpointAddress epoint = new EndpointAddress("net.tcp://localhost:9002/Contract/tcp");
        IContract proxy = ChannelFactory<IContract>.CreateChannel(new NetTcpBinding(), epoint);
        string xyz;
        using (proxy as IDisposable)
        {
            xyz = proxy.GetProperty;
        }

答案 1 :(得分:0)

我不确定你的合约.GepProperty是做什么的(但它不应该是第一个属性)

这可以按预期工作

---- ---- HOST

  static void Main(string[] args)
        {
            var svc = new ServiceHost(typeof(Service1));
            svc.Open();

            IChannelFactory<IService1> facContract = new ChannelFactory<IService1>(new NetTcpBinding());
            var contract = facContract.CreateChannel(new EndpointAddress("net.tcp://localhost:9002/Contract/tcp"));

            var x = contract.DoWork(); 
        }

---服务---

[ServiceContract]
public interface IService1
{
    [OperationContract]
    string DoWork();
}

// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
public class Service1 : IService1
{
    public string DoWork()
    {
        return "Hello Work.";
    }
}

---配置---

<configuration>
    <system.serviceModel>
        <services>
            <service name="HostAndClient.Service1">
                <endpoint address="Contract/tcp" binding="netTcpBinding" contract="HostAndClient.IService1">
                    <identity>
                        <dns value="localhost" />
                    </identity>
                </endpoint>
                <host>
                    <baseAddresses>
                        <add baseAddress="net.tcp://localhost:9002" />
                    </baseAddresses>
                </host>
            </service>
        </services>
    </system.serviceModel>
</configuration>