Configure WCF where ServiceContract and service implementation are in separate assemblies - c#

I've looked at a lot of questions on this site that discuss, but don't directly answer this question. I have the following:
In Library.dll:
namespace LibraryNamespace
{
[ServiceContract]
public interface IService
{
[OperationContract]
void Operation();
}
}
In Implementation.dll:
namespace ImplementationNamespace
{
public class ServiceImplementation : IService
{
public void Operation()
{
// Do Something
}
}
}
In app.config:
<service name="ImplementationNamespace.ServiceImplementation">
<endpoint
address="ServiceImplementation"
binding="netTcpBinding"
contract="LibraryNamespace.IService" />
....
</service>
And I keep having a warning with contract="LibraryNamespace.IService". The program runs, but I have a feeling this warning is causing me more problems down the line.
The 'contract' attribute is invalid - The value
'LibraryNamespace.IService' is invalid according to its datatype
'serviceContractType' - The Enumeration constraint has failed.
It works when the ServiceContract and the service implementation are in the same assembly and namespace, but for some reason, it doesn't work here. How can I reference it properly?

I am not sure Why do you want to have the contract and implementation in separate dll? any specific reason? Generally they will be in same assembly and so in config file you can refer them with ease. One way to solve this is creating the service endpoint at runtime like below.
In your hosting project refer both the dll Library.dll and Implementation.dll and have the below code to add the endpoint
using LibraryNamespace;
using ImplementationNamespace;
// Specify a base address for the service
String baseAddress = "http://localhost/ServiceImplementation";
// Create the tcp binding
NetTcpBindings tcp = new NetTcpBindings();
// Define service and Create the endpoint
using(ServiceHost host = new ServiceHost(typeof(ServiceImplementation)))
{
host.AddServiceEndpoint(typeof(IService),tcp, baseAddress);
}

Related

How to check wcf service is connected with client

I have created a WCF service in c#. Iam able to access it form a client app with url http://localhost:8080/classname/function
Is there any way to detect whether the client is connected from WCF service in which the client has the url http://localhost:8080 alone without class name and function name where the WCF service is listening to 8080 port at localhost?
Based upon your request to explain how to send an empty string message to a WCF service I have developed a VS2017 solution and uploaded onto the GITHUB for you.
The solution contain 3 projects, 2 on the WCF Service side (Class library and Console Application) and 1 for client.
WCF Service Side
First we define a ServiceContract that will have single OperationalContract to receive the string message and returns a boolean:
[ServiceContract]
public interface IClientConnectionService
{
[OperationContract]
bool Connect(string message);
}
Next, we have a class that implements this ServiceContract
public class ClientConnectionService : IClientConnectionService
{
public bool Connect(string message)
{
/*
* As per your comment on http://stackoverflow.com/questions/43366101/how-to-check-wcf-service-is-connected-with-client?noredirect=1#comment74005120_43366101
* the message should be empty, however you can pass string.
* Once you are done with processing you can return true or false depending upon how you want to carry out
* this operation.
*/
return true;
}
}
Next, we have the WCF service host manager (a console based application just to host this WCF service)
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(ClientConnectionService)))
{
host.Open();
Console.WriteLine($"{host.Description.Name} is up and listening on the URI given below. Press <enter> to exit.");
PrintServiceInfo(host.Description);
Console.ReadLine();
}
}
private static void PrintServiceInfo(ServiceDescription desc)
{
foreach (ServiceEndpoint nextEndpoint in desc.Endpoints)
{
Console.WriteLine(nextEndpoint.Address);
}
}
}
Its responsibility is to just keep the WCF service listening for incomming requests on a net.tcp port defined in the config file:
<system.serviceModel>
<services>
<service name="StackOverflow.Wcf.Services.ClientConnectionService">
<endpoint
address="net.tcp://localhost:9988/ClientConnectionService/"
binding="netTcpBinding"
contract="StackOverflow.Wcf.Services.Contracts.IClientConnectionService"
></endpoint>
</service>
</services>
</system.serviceModel>
Once this is completed we have a running WCF service. Now lets turn our attention to the client that will consume this service.
WCF Client Side
This is just a console application that has a reference of WCF Service and it creates the proxy class to call the method on the service.
public class ClientConnectionServiceProxy : ClientBase<IClientConnectionService>
{
public bool Connect(string message)
{
return base.Channel.Connect(message);
}
}
Notice that we have used IClientConnectionService interface / contract from the service side. ClientBase<T> is a WCF Framework class.
Here is the program class that calls the WCF servie using above defined proxy class.
class Program
{
static void Main(string[] args)
{
using (ClientConnectionServiceProxy proxy = new ClientConnectionServiceProxy())
{
bool isCallSuccessful = proxy.Connect(string.Empty);
}
}
}
and here is the client configuration:
<system.serviceModel>
<client>
<endpoint
address="net.tcp://localhost:9988/ClientConnectionService/"
binding="netTcpBinding"
contract="StackOverflow.Wcf.Services.Contracts.IClientConnectionService"
></endpoint>
</client>
</system.serviceModel>
How to run:
Once you have downloaded the source code from GITHUB, open the StackOverflow.Wcf.sln file in VS2017 (thats what I have used to develop this - not sure if you can open it in the VS2015) and hit F5. You can put break points to step through the code and edit it as you wish.
Hope this makes it clear - leave any questions in the comments below.

How to get rid of app.config and move it all into code?

I tried this question in a generic way on this post: https://stackoverflow.com/q/18968846/147637
But that did not get us to the result.
Soooo, here it is concretely!
I have the code below. It works. In VS, you add a web reference, code up the below, and then.... start fiddling the app.config.
And it works.
But I need to get rid of the app config. It is a problem that crucial pieces of the code are not in the.... code. It is hard to document, and easy for folks looking at this example to forget to look in the app config (this is an example for other devs).
So the question is: How do I move the contents of app.config into code?
(I am a part part part time coder. Pointing me at generic documentation won't get me there, sorry to say!)
**// .cs file:**
using myNameSpace.joesWebService.WebAPI.SOAP;
namespace myNameSpace
{
class Program
{
static void Main(string[] args)
{
// create the SOAP client
joesWebServerClient server = new joesWebServerClient();
string payloadXML = Loadpayload(filename);
// Run the SOAP transaction
string response = server.WebProcessShipment(string.Format("{0}#{1}", Username, Password), payloadXML);
=================================================
**app.config**
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<!-- Some non default stuff has been added by hand here -->
<binding name="IjoesWebServerbinding" maxBufferSize="256000000" maxReceivedMessageSize="256000000" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://joesWebServer/soap/IEntryPoint"
binding="basicHttpBinding" bindingConfiguration="IjoesWebServerbinding"
contract="myNameSpace.joesWebService.WebAPI.SOAP.IjoesWebServer"
name="IjoesWebServerSOAP" />
</client>
</system.serviceModel>
</configuration>
Generally speaking, a config file is preferred over hard-coding the settings because all you need to do with a config file is change the values you want to change and then restart the application. If they're hardcoded, you have to modify the source, recompile and redeploy.
Having said that, you can pretty much do everything in code that you do in the config file for WCF (I seem to recall a few exceptions, but don't remember them off hand).
One way to achieve what you're looking for is to define the binding in your code and create the client via ChannelFactory<T>, where T is the interface for your service (more accurately the service contract, which is usually in an interface and then implemented by a class).
For example:
using System.ServiceModel;
using myNameSpace.joesWebService.WebAPI.SOAP;
namespace myNameSpace
{
class Program
{
static void Main(string[] args)
{
// Create the binding
BasicHttpBinding myBinding = new BasicHttpBinding();
myBinding.MaxBufferSize = 256000000;
myBinding.MaxReceivedMessageSize = 256000000;
// Create the Channel Factory
ChannelFactory<IjoesWebServer> factory =
new ChannelFactory<IjoesWebServer>(myBinding, "http://joesWebServer/soap/IEntryPoint");
// Create, use and close the client
IjoesWebService client = null;
string payloadXML = Loadpayload(filename);
string response;
try
{
client = factory.CreateChannel();
((IClientChannel)client).Open();
response = client.WebProcessShipment(string.Format("{0}#{1}", Username, Password), payloadXML);
((IClientChannel)client).Close();
}
catch (Exception ex)
{
((ICientChannel)client).Abort();
// Do something with the error (ex.Message) here
}
}
}
Now you don't need a config file. The additional settings you had in the example are now in the code.
The advantage of ChannelFactory<T> is that once you create an instance of the factory, you can generate new channels (think of them as clients) at will by calling CreateChannel(). This will speed things up as most of your overhead will be in the creation of the factory.
An additional note - you're using I<name> in a lot of places in your config file. I usually denotes an interface, and if a full time developer were to look at your project it might be a little confusing for them at first glance.
With WCF 4.5, if you add a static config method to your WCF service class, then it will load automatically and ignore what's in app.config file.
<ServiceContract()>
Public Interface IWCFService
<OperationContract()>
Function GetData(ByVal value As Integer) As String
<OperationContract()>
Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType
End Interface
Public Class WCFService
Implements IWCFService
Public Shared Function CreateClient() As Object
End Function
Public Shared Sub Configure(config As ServiceConfiguration)
'Define service endpoint
config.AddServiceEndpoint(GetType(IWCFService), _
New NetNamedPipeBinding, _
New Uri("net.pipe://localhost/WCFService"))
'Define service behaviors
Dim myServiceBehaviors As New Description.ServiceDebugBehavior With {.IncludeExceptionDetailInFaults = True}
config.Description.Behaviors.Add(myServiceBehaviors)
End Sub
Public Function GetData(ByVal value As Integer) As String Implements IWCFService.GetData
Return String.Format("You entered: {0}", value)
End Function
Public Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType Implements IWCFService.GetDataUsingDataContract
End Function
End Class
I'm still looking into how to do the same for the client. I'll try to update when I figure it out if there's any interest.

Relationship between SVC files and WCF projects?

When creating a WCF project, the default member files are just ordinary csharp class files, rather than svc files. Are svc files required with a WCF project? When should they be used?
.svc files are used when you host your WCF service in IIS.
See Microsoft's doc here and here.
There's a module within IIS that handles the .svc file. Actually, it is the ASPNET ISAPI Module, which hands off the request for the .svc file to one of the handler factory types that has been configured for ASPNET, in this case
System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
If you are hosting your WCF service in something other than IIS, then you don't need the .svc file.
If you are using .net 4.0 or later, you can now "simulate" the .svc via config with the following:
<system.serviceModel>
<!-- bindings, endpoints, behaviors -->
<serviceHostingEnvironment >
<serviceActivations>
<add relativeAddress="MyService.svc" service="MyAssembly.MyService"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
Then you don't need a physical .svc file nor a global.asax
It is possible to create a WCF project and host it in IIS without using a .svc file.
Instead of implementing your DataContract in your svc code-behind, you implement it in a normal .cs file (i.e. no code behind.)
So, you would have a MyService.cs like this:
public class MyService: IMyService //IMyService defines the contract
{
[WebGet(UriTemplate = "resource/{externalResourceId}")]
public Resource GetResource(string externalResourceId)
{
int resourceId = 0;
if (!Int32.TryParse(externalResourceId, out resourceId) || externalResourceId == 0) // No ID or 0 provided
{
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
return null;
}
var resource = GetResource(resourceId);
return resource;
}
}
Then comes the thing making this possible. Now you need to create a Global.asax with code-behind where you add an Application_Start event hook:
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}
private void RegisterRoutes()
{
// Edit the base address of MyService by replacing the "MyService" string below
RouteTable.Routes.Add(new ServiceRoute("MyService", new WebServiceHostFactory(), typeof(MyService)));
}
}
One nice thing about this is that you don't have to handle the .svc in your resource URLs. One not so nice thing is that you now have a Global.asax file.

WCF service returning another service (service factory?)

We are using WCF for communication between a client and a server application. The client application has many features that requires communication to the server - and we have chosen to implement this in multiple classes (seperation of responsability)
For the time, we are creating new WCF endpoints and service contracts for each object - Invoicing, Accounting, Content Management, etc. This causes a lot of endpoint configuration both on the client and server (with potential misconfiguration problems when moving into the test and production platforms).
I would like to know if I can define a single WCF endpoint that can deliver multiple service contact implementations. Our configuration files would then contain a single endpoint (to the service factory) and I can request different services by specifying the interface of the service I am interested in.
e.g.
using (IServiceClientFactory serviceClientFactory = new RealProxyServiceClientFactory())
{
// This is normal WCF proxy object creation.
IServiceFactory serviceFactory = serviceClientFactory.CreateInstance<IServiceFactory>("");
// This is what we would like to do
IInvoiceService invoiceService = serviceFactory.getService(typeof(IInvoiceService));
invoiceService.executeOperation(data);
}
The clue being a single endpoint configuration per client/server pair, instead of an endpoint configuration per service contact I would like to make available.
Is this possible?
I'm not 100% clear on what you're trying to do, but if you just want to be able to host different contracts on the same address with the implementation inside one service class, this is completely possible. To share an endpoint address, you must ensure that you use the same binding instance for each service endpoint.
Here is a complete sample which defines 3 contracts, 1 service class which implements all of them, and a ServiceHost with the 3 contract endpoints at the exact same address:
using System;
using System.ServiceModel;
[ServiceContract]
interface IContractA
{
[OperationContract]
void A();
}
[ServiceContract]
interface IContractB
{
[OperationContract]
void B();
}
[ServiceContract]
interface IContractC
{
[OperationContract]
void C();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class Service : IContractA, IContractB, IContractC
{
public Service()
{
}
public void A()
{
Console.WriteLine("A");
}
public void B()
{
Console.WriteLine("B");
}
public void C()
{
Console.WriteLine("C");
}
}
class Program
{
public static void Main(string[] args)
{
Uri address = new Uri("net.pipe://localhost/Service/");
ServiceHost host = new ServiceHost(new Service(), address);
NetNamedPipeBinding binding = new NetNamedPipeBinding();
host.AddServiceEndpoint(typeof(IContractA), binding, string.Empty);
host.AddServiceEndpoint(typeof(IContractB), binding, string.Empty);
host.AddServiceEndpoint(typeof(IContractC), binding, string.Empty);
host.Open();
IContractA proxyA = ChannelFactory<IContractA>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyA.A();
((IClientChannel)proxyA).Close();
IContractB proxyB = ChannelFactory<IContractB>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyB.B();
((IClientChannel)proxyB).Close();
IContractC proxyC = ChannelFactory<IContractC>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyC.C();
((IClientChannel)proxyC).Close();
host.Close();
}
}
I doubt that this would work. Xml serialization might be the biggest problem here.
Also I don't think you actually need it. If I was in your shoes I would try and abstract my communication with the service. Basically you would always send a "Message" to the service, which has a "Target" being one of the classes you wanted to access. The service would always reply with a "Response", of which the contents would be filled by the class the "Message" was send to.
Another approach would be to route all these messages trough a service that would echo the request to the appropriate service. This way you keep scalability up, but it does still have a large configuration burden.
HTH.
Sounds like you want to keep your seperate services but have some kind of bus that routes is throught. MSMQ maybe, then you can have one services that takes every message pops it onto a specific queue and then a dedicated service can read that off that particular queue.
Not really a WCF based solution though admittedly.
The notion of a single interface(read as ServiceContract) implemented by multiple classes wont work. So you'd need one 'monster' service that implements all and routes through to the correct service. Facade pattern springs to mind.

Stop/start WCF MEX service at runtime

Is it possible/how do I stop and start the HTTP MEX listener of a self hosted WCF service at runtime without affecting the primary WCF service?
(Please don't ask why I want to do this. It is a hack to get around artificial limitations imposed by someone else.)
*****[Re-added this answer after re-test and code cleanup] This is actual code that I have added to my generic WCF-based service development framework and it is fully tested.*****
Assuming that you start with MEX enabled on the ServiceHost...
The following solution is written in
terms of a ServiceHost subclass
(WCFServiceHost<T>) that implements
a special interface (IWCFState) for
storing an instance of the MEX
EndpointDispatcher class.
First, add these namespaces...
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
Secondly, define the IWCFState interface...
public interface IWCFState
{
EndpointDispatcher MexEndpointDispatcher
{
get;
set;
}
}
Thirdly, create a static class for some ServiceHost extension methods (we'll fill them in below)...
public static class WCFExtensions
{
public static void RemoveMexEndpointDispatcher(this ServiceHost host){}
public static void AddMexEndpointDispatcher(this ServiceHost host){}
}
Now let's fill in the extension methods...
Stopping MEX on a ServiceHost at Runtime
public static void RemoveMexEndpointDispatcher(this ServiceHost host)
{
// In the simple example, we only define one MEX endpoint for
// one transport protocol
var queryMexChannelDisps =
host.ChannelDispatchers.Where(
disp => (((ChannelDispatcher)disp).Endpoints[0].ContractName
== "IMetadataExchange"));
var channelDisp = (ChannelDispatcher)queryMexChannelDisps.First();
// Save the MEX EndpointDispatcher
((IWCFState)host).MexEndpointDispatcher = channelDisp.Endpoints[0];
channelDisp.Endpoints.Remove(channelDisp.Endpoints[0]);
}
Then call it like this...
// WCFServiceHost<T> inherits from ServiceHost and T is the Service Type,
// with the new() condition for the generic type T. It encapsulates
// the creation of the Service Type that is passed into the base class
// constructor.
Uri baseAddress = new Uri("someValidURI");
WCFServiceHost<T> serviceImplementation = new WCFServiceHost<T>(baseAddress);
// We must open the ServiceHost first...
serviceImplementation.Open();
// Let's turn MEX off by default.
serviceImplementation.RemoveMexEndpointDispatcher();
Starting MEX (again) on a ServiceHost at Runtime
public static void AddMexEndpointDispatcher(this ServiceHost host)
{
var queryMexChannelDisps =
host.ChannelDispatchers.Where(
disp => (((ChannelDispatcher)disp).Endpoints.Count == 0));
var channelDisp = (ChannelDispatcher)queryMexChannelDisps.First();
// Add the MEX EndpointDispatcher
channelDisp.Endpoints.Add(((IWCFState)host).MexEndpointDispatcher);
}
Then call it like this...
serviceImplementation.AddMexEndpointDispatcher();
Summary
This design allows you to use some messaging methods to send a command to the service itself or to code that is hosting the service and have it carry out the enabling or disabling of a MEX EndpointDispatcher, effectively turning off MEX for that ServiceHost.
Note: This design assumes that the code will support MEX at startup, but then it will use a config setting to determine if the service will disable MEX after calling Open() on the ServiceHost. This code will throw if you attempt to call either extension method before the ServiceHost has been opened.
Considerations: I would probably create a special service instance with management operations that did not support MEX at startup and establish that as service control channel.
Resources
I found the following two resources indispensable while figuring this out:
.NET Reflector: class browser, analyzer & decompiler for inspecting assemblies like System.ServiceModel.dll: http://www.red-gate.com/products/reflector/
Extending Dispatchers (MSDN): provides a fantastic high-level diagram of the class composition of a WCF service: http://msdn.microsoft.com/en-us/library/ms734665.aspx

Categories