views:

2993

answers:

4

Hi,

I'm trying to communicate between WCF hosted in Windows Service and my service GUI. The problem is when I'm trying to execute OperationContract method I'm getting

"The ChannelDispatcher at 'net.tcp://localhost:7771/MyService' with contract(s) '"IContract"' is unable to open its IChannelListener."

My app.conf looks like that:

<configuration>
<system.serviceModel>
    <bindings>
        <netTcpBinding>
            <binding name="netTcpBinding">
                <security>
                    <transport protectionLevel="EncryptAndSign" />
                </security>
            </binding>
        </netTcpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="MyServiceBehavior">
                <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:7772/MyService" />
                <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <services>
        <service behaviorConfiguration="MyServiceBehavior"
            name="MyService.Service">
            <endpoint address="net.tcp://localhost:7771/MyService" binding="netTcpBinding"
                bindingConfiguration="netTcpBinding" name="netTcp" contract="MyService.IContract" />
        </service>
    </services>
</system.serviceModel>

Port 7771 is listening (checked using netstat) and svcutil is able to generate configs for me.

Any suggestions would be appreciated.


Stack trace from exception

Server stack trace: 
   at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)


There's one inner exeption (but not under Exeption.InnerExeption but under Exeption.Detail.InnerExeption - ToString() method doesn't show that)

A registration already exists for URI 'net.tcp://localhost:7771/MyService'.

But my service have specified this URI only in app.config file nowhere else. In entire solution this URI apears in server once and client once.

A: 

maybe the port is already used by another program on your machine, like an antivirus program? Or it's a Windows reserved port. Could you try setting the port to something like 11111?

Colin
unfortunately it's not. I've tried different ports (7771, 7772, 7773). Ports disapear from netstat output after turning off my service so probably nothing else is listening on them :/
kyrisu
A: 

I solved it :D

Here's the explanaition of the problem:

First BAD code:

namespace WCFServer
{
    public class Program : IWCFService
    {
        private ServiceHost host;

        static void Main(string[] args)
        {
            new Program();
        }

        public Program()
        {
            host = new ServiceHost(typeof(Program));

            host.Open();

            Console.WriteLine("Server Started!");

            Console.ReadKey();
        }

        #region IWCFService Members

        public int CheckHealth(int id)
        {
            return (1);
        }

        #endregion
    }
}

As you can see the service contract is implemented in class hosting the service. This caused the whole error thing (maybe typeof() runs a constructor, i don't know I'm open to constructive input in this matter).

The GOOD code:

namespace WCFServer
{
    public class Program
    {
        private ServiceHost host;

        static void Main(string[] args)
        {
            new Program();
        }

        public Program()
        {
            host = new ServiceHost(typeof(WCF));

            host.Open();

            Console.WriteLine("Server Started!");

            Console.ReadKey();
        }
    }

    public class WCF : IWCFService
    {

        #region IWCFService Members

        public int CheckHealth(int id)
        {
            return (1);
        }

        #endregion
    }
}

Service Contract for both files:

[ServiceContract]
public interface IWCFService
{
    [OperationContract]
    int CheckHealth(int id);
}

App.config

<configuration>
<system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior name="WCFBehavior" />
        </serviceBehaviors>
    </behaviors>
    <bindings>
        <netTcpBinding>
            <binding name="tcpBinding">
                <security>
                    <transport>
                        <extendedProtectionPolicy policyEnforcement="Never" />
                    </transport>
                </security>
            </binding>
        </netTcpBinding>
    </bindings>
    <services>
        <service name="WCFServer.WCF">
            <endpoint address="net.tcp://localhost:1111/TcpIHostMonitor" binding="netTcpBinding"
                bindingConfiguration="tcpBinding" name="netTcpEndpoint" contract="WCFServer.IWCFService" />
        </service>
    </services>
</system.serviceModel>

kyrisu
A: 

Hi, I had the same problem but I don't understand how did you solve it (It isn't a port problem either). This is my code:

Server App.Config

    <?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="serviceBehavior">
                    <serviceMetadata httpGetEnabled="false" />
                    <serviceCredentials>
                      <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Host.CustomUserNameValidator, Host" />
                    </serviceCredentials>
                </behavior>
              </serviceBehaviors>
        </behaviors>
        <services>
            <service behaviorConfiguration="serviceBehavior" name="BusinessServices.ServiceA">
                <endpoint address="ServiceA" binding="netTcpBinding" bindingConfiguration="TcpUserNameBinding"
                    contract="BusinessServiceContracts.IServiceA" bindingName ="" />
                <host>
                    <baseAddresses>
                        <add baseAddress="net.tcp://localhost:9000" />
                    </baseAddresses>
                </host>
            </service>
        </services>
    <bindings>
      <netTcpBinding>
        <binding name="TcpUserNameBinding">
          <security mode = "Transport">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
  </system.serviceModel>
</configuration>

Server Program.cs

ServiceHost host = new ServiceHost(typeof(ServiceA));
host.Open();
Console.WriteLine("Host listening ...");
Console.ReadLine();

CustomUserNameValidator (class for Validate the user's credentials)

public class CustomUserNameValidator : UserNamePasswordValidator
{
  public override void Validate(string userName, string password)
  {
    if (null == userName || null == password) {
      throw new ArgumentNullException();
    }

    if (!(userName == "pippo" && password == "miaPassword")) {
      throw new FaultException("Unknown Username or Incorrect Password");
    }
  }
}

Client App.Config

<system.serviceModel>
<client>
  <endpoint address="net.tcp://localhost:9000/ServiceA" contract="BusinessServiceContracts.IServiceA" binding="netTcpBinding" bindingConfiguration="Binding1" />
</client>
<bindings>
  <netTcpBinding>
    <binding name="binding1">
      <security mode="Transport">
        <message clientCredentialType="UserName"/>
      </security>
    </binding>
  </netTcpBinding>
</bindings>

Client Form1.cs

ChannelFactory<IServiceA> factoryA = new ChannelFactory<IServiceA>("");
factoryA.Credentials.UserName.UserName = "pippo";
factoryA.Credentials.UserName.Password = "miaPassword";
m_proxyA = factoryA.CreateChannel();
m_proxyA.Operation1();

Validate function is never called. Why? Thank's in advance.

Spighy

Spighy
A: 

With this type of exception it's the Inner exception that has the information that is useful to diagnose the problem. This is a rather generic error that could be caused by a bunch of different things.

Nate Zaugg