0

I'm trying to switch from programmatically setting the endpoint to using the config file. The problem is that when I use the config file, there is no error thrown, but the tcp port is not opened, and clients cannot connect.

This is netstat showing the port being opened when programmatically set, and then with the config file. netstat output

The following is my complete example client server and contracts app.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>   
        <services>
            <service name="Server.CustomerService">
                <endpoint 
                    address="net.tcp://localhost:8081/CustomerService"
                    binding="netTcpBinding"
                    contract="Shared.ICustomerService"/>
            </service>
        </services>
    </system.serviceModel>
</configuration>

Server:

class ProgramService
    {
        static List<Customer> _customers = new List<Customer>();
        static void Main(string[] args)
        {
            CreateCustomers();
            Uri netTCPObject = new Uri("net.tcp://localhost:8081/CustomerService");
            ServiceHost sessionHost = new ServiceHost(typeof(CustomerService), netTCPObject);
            //ServiceHost sessionHost = new ServiceHost("Server.CustomerService");  //using the app.config

            sessionHost.Open();

            Console.WriteLine("Service is running");
            Console.ReadLine();
            sessionHost.Close();
        }

        private static void CreateCustomers()
        {
            _customers.Add(new Customer() { CustomerId = 1, FirstName = "Fred", LastName = "Flintstone" });
            _customers.Add(new Customer() { CustomerId = 2, FirstName = "John", LastName = "Doe" });
            _customers.Add(new Customer() { CustomerId = 3, FirstName = "Rebecca", LastName = "Johndaughter" });
            _customers.Add(new Customer() { CustomerId = 4, FirstName = "Julie", LastName = "Herald" });
        }

        public class CustomerService : ICustomerService
        {
            public Customer GetCustomer(int customerId)
            {
                return _customers.FirstOrDefault(c => c.CustomerId == customerId);
            }

            public bool UpdateCustomer(Customer customer)
            {
                var curCust = _customers.FirstOrDefault(c => c.CustomerId == customer.CustomerId);
                if (curCust != null)
                {
                    curCust.FirstName = customer.FirstName;
                    curCust.LastName = customer.LastName;
                }
                else
                {
                    _customers.Add(customer);
                }
                return true;
            }
        }
    }

Contracts:

namespace Shared
{
    [ServiceContract()]
    public interface ICustomerService
    {
        [OperationContract]
        Customer GetCustomer(int customerId);

        [OperationContract]
        bool UpdateCustomer(Customer customer);
    }

    [DataContract]
    public class Customer
    {
        [DataMember]
        public string FirstName { get; set; }

        [DataMember]
        public string LastName { get; set; }

        [DataMember]
        public int CustomerId { get; set; }
    }
}

Client:

class ProgramClient
{
    static void Main(string[] args)
    {
        //http://stackoverflow.com/a/2943206/232226
        NetTcpBinding binding = new NetTcpBinding();
        EndpointAddress endpoint = new EndpointAddress("net.tcp://localhost:8081/CustomerService");
        ChannelFactory<ICustomerService> factory =  new ChannelFactory<ICustomerService>(binding, endpoint);

        ICustomerService service = factory.CreateChannel();
        for (int i = 1; i < 5; i++)
        {
            Customer customer = service.GetCustomer(i);
            Console.WriteLine(String.Format("  Customer {0} {1} received.", customer.FirstName, customer.LastName));
        }
        Console.ReadLine();
    }
}
ToddK
  • 765
  • 9
  • 16
  • Because your configured service name doesn't correspond to the name of the service. It should be ``. – CodeCaster Jun 23 '16 at 19:00
  • So using the string constructor, you cannot use whatever name you want? new ServiceHost("Server.CustomerService"); – ToddK Jun 23 '16 at 19:30
  • So, I did as suggested, changing the name in the config, and updating the name in the ServiceHost constructor, but that did not help. Note to run this example with the config file, you need to uncomment the second ServiceHost instantiation and comment out the first. – ToddK Jun 23 '16 at 19:34
  • I missed that your service is a nested class. Your `ProgramService` is in its own namespace. You need to prepend that namespace as well, so you need `SomeNamespace.ProgramService.CustomerService` as the service name in the configuration. And no, you can't just pass a string to ServiceHost, you need to pass the type and the type alone. – CodeCaster Jun 23 '16 at 19:36
  • My namespace is wcfService, so I updated the config to be this: and updated the instantiation to be this: ServiceHost sessionHost = new ServiceHost("wcfService.ProgramService.CustomerService"); but that did not help. – ToddK Jun 23 '16 at 19:40
  • With "did not help" we can't do much, please post exactly what happens. Anyway see the edit, you should not be passing a string there, but a type (`new ServiceHost(typeof(CustomerService))`). – CodeCaster Jun 23 '16 at 19:41
  • Ah, its a type, the other constructor overload take an Object, so that's why it compiles and runs. Too bad it didn't throw. So, I changed it to use the type and it throws 'wcfService.ProgramService+CustomerService' has zero application (non-infrastructure) endpoints, but they are there in the config. I double checked the spelling of the service name and the contract on the endpoint. – ToddK Jun 23 '16 at 19:53
  • Ok got it working. What tripped it up was that since my Service is a class within a class, the name needed to use a plus sign between the outer and inner class names. So it looks like this now: – ToddK Jun 23 '16 at 19:57
  • @CodeCaster, if you put your comment about it needing a type as an answer, I will go ahead and accept it. – ToddK Jun 23 '16 at 19:59

1 Answers1

1

The ServiceHost constructor has an overload accepting a Type and one accepting an object, either being a type or an instance of a service class.

This means that new ServiceHost("someString") will call the object overload, which is going to throw an exception because string does not implement a service.

You need to call it with your service type:

var serviceHost = new ServiceHost(typeof(CustomerService))

And in configuration, use the full name of the type:

<service name="ServiceNamespace.ProgramService.CustomerService">
CodeCaster
  • 147,647
  • 23
  • 218
  • 272