Host multiple contracts in one WCF service [duplicate] - c#

This question already has answers here:
Run WCF ServiceHost with multiple contracts
(8 answers)
Closed 9 years ago.
Is it possible to host multiple service contracts in one WCF service? If so, how? I've been googling and some posts say you can do it (but not how) and others have said it's just not possible.
When I run the server, I get this error:
The contract name 'ConsoleAppWcfCommon.IBarService' could not be found
in the list of contracts implemented by the service
'ConsoleAppWcfServer.FooService'.
This is my server code:
static void Main(string[] args)
{
string serviceAddress = "net.tcp://localhost:8088/FooBarService";
// I'm stuck here as I have to pick *one* service
ServiceHost selfServiceHost = new ServiceHost(typeof(FooService));
// I can add both endpoints here, but this is what gives me the error.
selfServiceHost.AddServiceEndpoint(typeof(IFooService), new NetTcpBinding(), serviceAddress);
selfServiceHost.AddServiceEndpoint(typeof(IBarService), new NetTcpBinding(), serviceAddress);
selfServiceHost.Open();
Console.ReadLine();
selfServiceHost.Close();
}
And this is the client code:
static void Main(string[] args)
{
NetTcpBinding netTcpBinding = new NetTcpBinding();
EndpointAddress endpointAddress = new EndpointAddress("net.tcp://localhost:8088/FooBarService");
// Call IFooService
var channelFactoryFoo = new ChannelFactory<IFooService>(netTcpBinding, endpointAddress);
IFooService channelFoo = channelFactoryFoo.CreateChannel();
Debug.WriteLine(channelFoo.FooMethod1());
// Call IBarService
var channelFactoryBar = new ChannelFactory<IBarService>(netTcpBinding, endpointAddress);
IBarService channelBar = channelFactoryBar.CreateChannel();
Debug.WriteLine(channelBar.BarMethod1());
}
My goal is to let the client make a call to Foo (or Bar) and only see the methods available to each. In my real application, I have about 10 domain entities with about four operations on each. I'm trying not to have one interface with 40 methods in it. And I don't want to have to host 10 different WCF services to do this.

As marc_s pointed out, the answer was to have one service implementation class that implements both interfaces. Below is the full working code.
Server:
static void Main(string[] args)
{
string serviceAddress = "net.tcp://localhost:8088/FooBarService";
ServiceHost selfServiceHost = new ServiceHost(typeof(FooService));
// The endpoints need to share this binding.
var binding = new NetTcpBinding();
selfServiceHost.AddServiceEndpoint(typeof(IFooService), binding, serviceAddress);
selfServiceHost.AddServiceEndpoint(typeof(IBarService), binding, serviceAddress);
selfServiceHost.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press any key to terminate service.");
Console.WriteLine();
Console.ReadKey();
selfServiceHost.Close();
}
Client:
static void Main(string[] args)
{
NetTcpBinding netTcpBinding = new NetTcpBinding();
EndpointAddress endpointAddress = new EndpointAddress("net.tcp://localhost:8088/FooBarService");
// Call IFooService
var channelFactoryFoo = new ChannelFactory<IFooService>(netTcpBinding, endpointAddress);
IFooService channelFoo = channelFactoryFoo.CreateChannel();
Console.WriteLine(channelFoo.FooMethod1());
// Call IBarService
var channelFactoryBar = new ChannelFactory<IBarService>(netTcpBinding, endpointAddress);
IBarService channelBar = channelFactoryBar.CreateChannel();
Console.WriteLine(channelBar.BarMethod1());
Console.ReadKey();
}
Foo Contract:
[ServiceContract]
public interface IFooService
{
[OperationContract]
string FooMethod1();
[OperationContract]
string FooMethod2();
}
Bar Contract:
[ServiceContract]
public interface IBarService
{
[OperationContract]
string BarMethod1();
[OperationContract]
string BarMethod2();
}
Foo Service:
public class FooService : IFooService, IBarService
{
public string FooMethod1()
{
return "FooMethod1";
}
public string FooMethod2()
{
return "FooMethod2";
}
public string BarMethod1()
{
return "BarMethod1";
}
public string BarMethod2()
{
return "BarMethod2";
}
}

Related

Timeout Exception during call from wpf client to server in one solution

What is the problem: System.TimeoutException: 'The request channel timed out while waiting for a reply after 00:00:59.977913. So, basically it can be everything.
What do I have:
I create a simple solution to found a fix. What really make me confused is that console app works just fine, however wpf app with same configuration does not work. Solution include four projects(code made for debugging purpose, please don't judge it):
library with contracts and their implementation.
public class DeviceService : IDeviceService
{
public string GetDevices()
{
return "hello world";
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
library with host.
public class DeviceServiceHostFactory
{
ServiceHost host;
public DeviceServiceHostFactory()
{
ServiceMetadataBehavior metadataBehavior;
BasicHttpBinding binding = new BasicHttpBinding();
Uri address = new Uri("http://localhost:4000/");
host = new ServiceHost(typeof(DeviceService), address);
Type contract = typeof(IDeviceService);
host.AddServiceEndpoint(contract, binding, "");
}
public void Start()
{
host.Open();
}
public void Stop()
{
host.Close();
}
}
desktop app that start service and consume it (does not work)
public partial class MainWindow : Window
{
private DeviceServiceHostFactory _deviceService;
public MainWindow()
{
InitializeComponent();
try
{
_deviceService = new DeviceServiceHostFactory();
_deviceService.Start();
}
catch (Exception ex)
{
_deviceService.Stop();
Console.WriteLine(ex.StackTrace);
}
}
private void Btn_custom_Click(object sender, RoutedEventArgs e)
{
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint =
new EndpointAddress("http://localhost:4000/");
var factory =
new ChannelFactory<IDeviceService>(
binding, endpoint);
var channel = factory.CreateChannel();
txt_custom.Text = channel.GetDevices();
Console.WriteLine();
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
console app (works fine)
class Program
{
static void Main(string[] args)
{
DeviceServiceHostFactory _deviceService = new
DeviceServiceHostFactory();
try
{
_deviceService.Start();
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint =
new EndpointAddress("http://localhost:4000/");
var factory =
new ChannelFactory<IDeviceService>(
binding, endpoint);
var channel = factory.CreateChannel();
Console.WriteLine(channel.GetDevices());
Console.ReadLine();
}
catch (Exception ex)
{
_deviceService.Stop();
Console.WriteLine(ex.StackTrace);
}
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
I really spend a lot of time for this, and I will be very grateful for every solution or thought how can I debug it more advanced.
Hosting wcf service in application with UI is little bit tricky, so I hope this will help someone.
Took it from book Learning WCF: A hands-On Guide By Michele Leroux Bustamante, Chapter 4, so fo more information please find this book.
To host service in Windows application or WPF application, we have to create a new thread to start it in a new synchronization context. It can be done in two ways:
First, is to create service host before the UI thread created. Here service executes in a new synchronization contenxt before application starts.
static class Program
{
static void Main()
{
DeviceServiceHostFactory deviceService = new DeviceServiceHostFactory();
deviceService.Start();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow);
}
}
Second, is to initialize service host on a separate thread, after UI been created
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Thread thread;
thread = new Thread(ServiceInitialize);
thread.IsBackground = true;
thread.Start();
}
private void ServiceInitialize()
{
var service = new DeviceServiceHostFactory();
service.Start();
}
}
This means the messages are processed on threads form the thread pool instead of through the message loop.
First, we should give the current account permissions when we occupy the Operation system ports to host services.
This function could be accomplished by the below command.
Netsh http add urlacl url=https://+:80/MyUri user=DOMAIN\user
https://learn.microsoft.com/en-us/windows/win32/http/add-urlacl
If we don’t want to do this, we could directly run the service with administrator accounts.
Thereby I suspect there is something wrong with the process of hosting the service. Have you tried running the WPF application with an administrator account?
Besides, I suggest you add a namespace in the service contract.
[ServiceContract(Namespace ="MyNamespace")]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
Sometimes, it could run into problems when the service contract doesn’t have a namespace property.
Feel free to let me know if the problem still exists.

Cannot access a disposed object when calling callback method

I've a Duplex TCP IP WCF service. I'm currently unit-testing it.
In everyone of my test, I setup a new server, create a new ChannelFactory, create the InstanceContext and do the call.
Then I trigger the event(it's a Mock on the server side), and the server give me this exception when it tries to reach the client:
Exception thrown: 'System.ObjectDisposedException' in mscorlib.dll
Additional information: Cannot access a disposed object.
Important point, this happens ONLY when I run all the tests in a row(sequentially executed but in the same execution).
There is nothing special about my service:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IMyServiceCallback))]
public interface IMyService{
[OperationContract]
void SomeVariousMethods();
}
[ServiceContract]
public interface IMyServiceCallback
{
[OperationContract]
void HandleMessageFromServer(String message);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService{
public MyService(ISomeServerComponent component){
component.OnMessage += OnMessageReceived;
}
public void SomeVariousMethods(){
//...
}
private void OnMessageReceived(object sender, EventArgs<String> e){
IMyServiceCallback callback = OperationContext.Current.GetCallbackChannel<IMyServiceCallback>();
callBack.HandleMessageFromServer(e.Data);//Crash here
}
}
And here is how I'm currently UnitTesting it(not exactly, I've a lot of this that has been extracted in some helpers:
[TestFixture]
public class MyServiceTest:IMyServiceCallback{
private Mock<ISomeServerComponent> _mock;
[OneTimeSetUp]
public void Setup(){
//... Creating a mock for the ISomeServerComponent that the MyService receives
}
[Test]
public void TestSomeVariousMethods(){
string serviceName = nameof(TestSomeVariousMethods);
using(ServiceHost host = CreateServer(_mock.Object,serviceName)){
using (IMyService service = CreateClient(serviceName, this)){
service.SomeVariousMethods();
}
}
}
[Test]
public void TestCallback(){
string serviceName = nameof(TestSomeVariousMethods);
using(ServiceHost host = CreateServer(_mock.Object,serviceName)){
using (IMyService service = CreateClient(serviceName, this)){
_mock.TriggerCallBack();
//Assert-that-the-flag-has-been-set
}
}
}
public void HandleMessageFromServer(String msg){
//Flag that this method has been called
}
private ServiceHost CreateServer(ISomeServerComponent mock, string serviceName){
UnityServiceHost serviceHost = new UnityServiceHost(m_container);//This extends ServiceHost to be able to inject some objects to my services
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
binding.ReliableSession.Enabled = true;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
binding.MaxBufferPoolSize = Int64.MaxValue;
binding.MaxBufferSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
Uri uri = new Uri(String.Format("net.tcp://{0}:{1}/{2}", IPAddress.Any, 9999, serviceName));
ServiceEndpoint serviceEndpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(IMyService)), binding, uri);
serviceEndpoint.EndpointBehaviors.Add(new ProtoEndpointBehavior());
serviceHost.AddServiceEndpoint(serviceEndpoint);
return serviceHost;
}
private IMyService CreateClient(string serviceName, IMyServiceCallback callback){
UnityServiceHost serviceHost = new UnityServiceHost(m_container);//This extends ServiceHost to be able to inject some objects to my services
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
binding.ReliableSession.Enabled = true;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
binding.MaxBufferPoolSize = Int64.MaxValue;
binding.MaxBufferSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
Uri uri = new Uri(String.Format("net.tcp://{0}:{1}/{2}", IPAddress.Loopback, 9999, serviceName));
InstanceContext context = new InstanceContext(callBack);
DuplexChannelFactory channelFactory = new DuplexChannelFactory<T>(context, binding, new EndpointAddress(uri));
return channelFactory.CreateChannel()
}
}
Funny part is that all of this works when I'm ONLY running TestCallback test, but if I run all the test of the class, it fails, like if the second time, the InstanceContext was not creating properly the callback.
Any idea how to avoid this?
I finally found the issue. I feel a little bit stupid, but in fact, in the Service implementation, I was not unregistering from the OnMessage correctly, so when the event was triggered, the previous service instance were trying to communicate with the already closed client.

NetTcpBinding - Self-Hosted WCF - Can't get client connected

Trying to get a simple demo of NetTcpBinding working in order to expand it into another project.
Architecture: 2 console apps (1 host/server, 1 client) and 1 type library project. Both console apps have a reference to the type library project.
Host application:
class Program
{
static void Main()
{
var netTcpBinding = new NetTcpBinding(SecurityMode.None)
{
PortSharingEnabled = true
};
var netTcpAdddress = new Uri("net.tcp://127.0.0.1:1234/HelloWorldService/");
var tcpHost = new ServiceHost(typeof(HelloWorldService), netTcpAdddress);
tcpHost.AddServiceEndpoint(typeof(IHelloWorld), netTcpBinding, "IHelloWorld");
tcpHost.Open();
Console.WriteLine($"tcpHost is {tcpHost.State}. Press enter to close.");
Console.ReadLine();
tcpHost.Close();
}
}
public class HelloWorldService : IHelloWorld
{
public void HelloWorld()
{
Console.WriteLine("Hello World!");
}
public void WriteMe(string text)
{
Console.WriteLine($"WriteMe: {text}");
}
}
Client application:
static void Main()
{
Console.WriteLine("Press enter when the service is opened.");
Console.ReadLine();
var endPoint = new EndpointAddress("net.tcp://127.0.0.1:1234/HelloWorldService/");
var binding = new NetTcpBinding ();
var channel = new ChannelFactory<IHelloWorld>(binding, endPoint);
var client = channel.CreateChannel();
try
{
Console.WriteLine("Invoking HelloWorld on TcpService.");
client.HelloWorld();
Console.WriteLine("Successful.");
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
Console.WriteLine("Press enter to quit.");
Console.ReadLine();
}
Type Library:
[ServiceContract]
public interface IHelloWorld
{
[OperationContract]
void HelloWorld();
[OperationContract]
void WriteMe(string text);
}
I believe I have all necessary services installed and running:
Obviously I'm trying to do all the config at runtime.
I consistently get this error message on the client:
Invoking HelloWorld on TcpService.
Exception: There was no endpoint listening at
net.tcp://127.0.0.1:1234/HelloWorldService/ that could accept the
message. This is often caused by an incorrect address or SOAP action.
See InnerException, if present, for more details. Press enter to quit.
Am I missing something obvious?
Your service is exposing the endpoint at address:
net.tcp://127.0.0.1:1234/HelloWorldService/IHelloWorld
but your client is connecting to:
net.tcp://127.0.0.1:1234/HelloWorldService/
You'll also need to set the client NetTcpBinding SecurityMode the same as the server (None).

Inject parameter at WCF service constructor using NInject

I've seen several examples on Internet setting up an NInject Factory modifying svc file. I don't have this svc file (or I don't know where's it).
I've a slight WCF service:
IService interface:
[ServiceContract]
public interface IFileSystemPluginService
{
[OperationContract]
void saveConfiguration(Configuration.Configuration configuration, string userId);
[OperationContract]
Configuration.Configuration getConfiguration(string userId);
}
IService implementation:
public class Service : IService
{
private IUserConfigurable userConfigurablePlugin;
public Service(IUserConfigurable configurablePlugin)
{
this.configurablePlugin = configurablePlugin;
}
}
In order to kick the service off I'm setting configuration up in code:
private void initializeWCFService()
{
string baseAdress = "xxx";
Uri baseAddressUri = new Uri(baseAdress);
this.serviceHost = new System.ServiceModel.ServiceHost(typeof(Service), baseAddressUri);
this.serviceHost.AddServiceEndpoint(
typeof(IService),
new System.ServiceModel.WSHttpBinding(),
string.Empty
);
System.ServiceModel.Description.ServiceMetadataBehavior smb = new System.ServiceModel.Description.ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri(baseAdress);
this.serviceHost.Description.Behaviors.Add(smb);
this.serviceHost.Open();
}
I need to inject a IUserConfigurable object in Service constructor.

writing a regression test for a wcf service with client

I would like to write an automated regression test whereby my service is started and I can assert that my client can retrieve some things from the service.
Private Blah proxy;
[SetUp]
public void SetUp()
{
proxy= new Blah();
}
[Test]
public void GetStuff()
{
var result = proxy.GetStuff();
Assert.NotNull(result);
}
This doesn't work because my service isn't running. How would I make start my service before the tests?
For integration/acceptance testing of WCF services I suggest you to use Self Hosted WCF Service. Examples you can find here:
Creating a Self Hosted WCF Service
Self Hosting Windows Communication Foundation Services
Create self-hosted service on fixture setup, and close it on fixture tear down:
EndpointAddress address = new EndpointAddress("http://localhost:8080/service1");
ServiceHost host;
IService1 service;
[TestFixtureSetUp]
public void FixtureSetUp()
{
var binding = new BasicHttpBinding();
host = new ServiceHost(typeof(Service1), address.Uri);
host.AddServiceEndpoint(typeof(IService1), binding, address.Uri);
host.Open();
}
[TestFixtureTearDown]
public void FixtureTearDown()
{
if (host == null)
return;
if (host.State == CommunicationState.Opened)
host.Close();
else if (host.State == CommunicationState.Faulted)
host.Abort();
}
With service hosted you can get service proxy:
var binding = new BasicHttpBinding();
ChannelFactory<IService1> factory =
new ChannelFactory<IService1>(binding, address);
service = factory.CreateChannel();
And your test will look like:
[Test]
public void ShouldReturnSomeStuff()
{
var result = service.GetStuff();
Assert.NotNull(result);
}

Categories

Resources