Abdi Getachew Abdi Getachew - 10 days ago 6
C# Question

windows form application calling a WCF service and the WCF service calling another WCF service

This is a sample project I built to test service calling another service

This is the Service that gets called by the other service

namespace WCFPub
{
[ServiceContract]
public interface IStudent
{
[OperationContract]
string getName(string name);
}

}

namespace WCFPub
{
public class Student : IStudent
{
public string getName(string name)
{
return "Your name is " + name;
}
}
}


Console application that hosts the above service

namespace WCFHost
{
class Program
{
static void Main(string[] args)
{
try
{
ServiceHost sh = new ServiceHost(typeof(WCFPub.Student));
ServiceMetadataBehavior serviceMetadataBehaviour = new ServiceMetadataBehavior()
{
HttpGetEnabled = true,

};
sh.Description.Behaviors.Add(serviceMetadataBehaviour);
sh.AddServiceEndpoint(typeof(WCFPub.IStudent), new WSDualHttpBinding(), "PS");
Console.WriteLine("Host Ready, Listening on 7060");
Console.WriteLine("Hit Enter to Stop..");
sh.Open();
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

}
}
}


Service that calls the second service

namespace WCFPub2
{
[ServiceContract]
public interface IMaster
{
[OperationContract]
string getNameFromStudent(string name);
}

}

namespace WCFPub2
{

public class Master : IMaster
{
public string getNameFromStudent(string name)
{
Proxy2.StudentClient client = new Proxy2.StudentClient();
return client.getName("ABdi");
}
}
}


The console app that hosts the above service

namespace WCFHost2
{
class Program
{
static void Main(string[] args)
{
try
{
ServiceHost sh = new ServiceHost(typeof(WCFPub2.Master));
ServiceMetadataBehavior serviceMetadataBehaviour = new ServiceMetadataBehavior()
{
HttpGetEnabled = true,

};
sh.Description.Behaviors.Add(serviceMetadataBehaviour);
sh.AddServiceEndpoint(typeof(WCFPub2.IMaster), new WSDualHttpBinding(), "PS");
Console.WriteLine("Host Ready, Listening on 7061");
Console.WriteLine("Hit Enter to Stop..");
sh.Open();
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

}
}
}


The Client

namespace WCFClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{

Proxy.MasterClient client = new Proxy.MasterClient();
MessageBox.Show(client.getNameFromStudent("ABdi"));
}
}
}


This doesn't work and throws an exception


System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]:

Could not find default endpoint element that references contract 'Proxy2.IStudent' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.

(Fault Detail is equal to An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is:

System.InvalidOperationException: Could not find default endpoint element that references contract 'Proxy2.IStudent' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.

at System.ServiceModel.Description.ConfigLoader.LoadChannelBehaviors(ServiceEndpoint serviceEndpoint, String configurationName)

at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName, Configuration configuration)

at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName)

at System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address)

at System.ServiceModel.ChannelFactory`1..ctor(String endpointConfigurationName, EndpointAddress remoteAddress)

at System.ServiceModel.Configu...).


I need help please

Answer

I don't see where you specify addresses for services and clients (I don't see for ex. Host = new ServiceHost(new Service.BossService(), baseUrl); or new Proxy.MasterClient(endpointConfiguraionName) or Proxy.MasterClient(binding, baseAddress)). If you are using config files everywhere (with addresses in it), then you do not need any extra steps for setting up services (Behaviors.Add, ...AddServiceEndpoint) - all service creation steps will be performed automatically by using config.

My recommendations:

1) Remove all service hosting code, use only config file-based configuration (including base address, which can be relative if you are hosting in *.svc or absolute). This is much more flexible and convenient way (if you have possibility to use config files, coz sometimes you don't have) - I used it for years. See simple wcf configuration example)

2) Use singletone instance (as more predictable). Finally you will have just one line of code like Host = new ServiceHost(new MyService()).

3) Do not use generated (svcutil) wcf client code. Just share contracts library (service contracts, data contracts) between service and client. And then use ChannelFactory to call service methods: Channel = new ChannelFactory<MyService>("bindingConfigurationName").CreateChannel() or new ChannelFactory<MyService>(binding, serviceAddress).CreateChannel(). This is just fine and enough to call service methods synchronously (with some extra work you can even call service methods asynchronously by knowing and using simple synchronous service interface!)

4) Do not use WSDualHttpBinding - it does not work as it should (at least over internet and firewalls). I recommend tcpbinding (duplex by nature, works good almost everywhere). But if you use WSDualHttpBinding - why don't you have bidirectional methods (duplex contract, see example)?

5) Test you services with standard clients like wcftestclient, SoapUI, or even fiddler or postman (for RESTful services).