To use your WCF service with a WCF client you will need to get access to the service. WCF does this by supplying a transparent proxy of the service to your client. This can then be used to invoke remote methods on the service.

So in this post we will look into the ways to generate such proxy.

What does this post cover

  • General overview over proxy call forwarding
  • Generating a proxy with Visual Studio
  • Generating a proxy with SvcUtil.exe
  • Parts of programmatic and administrative client configuration
  • Use Channel factory to invoke service methods directly

What does this post not cover

  • How to create a service
  • Configuration of WCF services
  • WCF architecture

Alternatives

I’ll show you three different possibilities to create a client proxy, others would be to consume the WCF generated WSDL. But this only makes sense if you are not using WCF on the client side. Else you would gain pretty much nothing but more overhead and complexity. If you want to fine tune the proxy generation better use the extensibility and interception capabilities of WCF.

How does a service call work in general

In general WCF needs a proxy to let a client request a method of the given WCF service. The client then uses this proxy to forward a method call of the specified service contract.
This forwarded call goes throught the appropriate Channels to create the SOAP message, applies the configured behaviors, is then forwarded to the instance context, in which the service instance is hosted, and finally is executed there. If the call returns at the service, it returns in the same way through all the appropriate channels.

To invoke a proxy, the client needs a way to import the service description first.
The imported proxy equalsCLR interface with the same representation as the service contract. For each servicetype per endpoint that the client should use you will need to supply a specific proxy to the client.

Use of proxy and generating proxies

Besides the operations of the service, the proxy has lifecycle related methods and connection related methods.
To make the programming interface as convenient as possible for application programmers the proxy encapsulates every aspect of the service. Which includes the location, the implementation, the technology, runtime platform, transport scheme, and servicebehavior.

To utilize a proxy on the client side in a performant manner, a best practice is to always Close the client if you are finished with the given call.

We are now going to look into the first way to generate a proxy which is via Visual studio and a self-hosted WCF service.

Generate a Proxy with Visual Studio

As described above you ‘ll need to discover the service first to utilize it with a proxy at client side. There are two industry standards to infer the service information. The first one is the use of http-Get for your metadata. For this you simply add a service endpoint that exposes your service with HttpBinding. The other is the notion of a MetadataExchange (MEX) Endpoint. (To run your process with an http endpoint make sure to run VS as an admdinistrator.)

For the upcoming examples we are using the following Servicecontract and implementation:

[ServiceContract(Name ="myService", Namespace ="http://mywcf/"
, SessionMode =SessionMode.Required)]
public interface IMyService
{
    [OperationContract(IsInitiating = true)]
    void Connect();

    [OperationContract(IsInitiating = false)]
    string ReturnName();

    [OperationContract(IsTerminating = true)]
    void Disconnect();
}

// Implementation:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
internal class ServiceImplementation : IMyService
{
    static List<string> _clients = new List<string>();
    public void Connect()
    {
        var sessionId = OperationContext.Current.SessionId;
        if (!_clients.Contains(sessionId))
        {
           _clients.Add(sessionId);
        }
    }

    public void Disconnect()
    {
        _clients.Remove(OperationContext.Current.SessionId);
    }

    public string ReturnName()
    {
        return nameof(ServiceImplementation);
    }  
}

 

Then add MEX endpoint like the following snippet. Use either programmatic or adiminstrative configuration (but recall I personally prefer programmatic)

var serviceHost = new ServiceHost(typeof(IMyService));
var meta = serviceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (meta == null)
{
    meta = new ServiceMetadataBehavior();
    serviceHost.Description.Behaviors.Add(meta);
}
var endpoint = new ServiceMetadataEndpoint(new EndpointAddress("http://localhost:801/MEX"));
serviceHost.AddServiceEndpoint(endpoint);

serviceHost.Open();

// or administratively:
<services>
   <service name="MyService" behaviorconfiguration="MEX">
      <host>
         <baseAddresses>
            <add baseAddress = "net.tcp://localhost:8001/"/>
         </baseAddresses>
      </host>
     <endpoint
        address = "http://localhost:801/MEX"
        binding = "mexHttpBinding"
        contract="IMetadataExchange"/>
    </service>
</services>

If you have set up your WCF service and are hosting it in your self-hosting process you will need to take the following steps:

  1. Start your service self-hosting process without debugging (as administrator for MEX http rights)
  2. Open your Solution with the client
  3. Rigth click References of the assembly
  4. choose AddService Reference from context menu
  5. follow the instructions in the dialog (see below)

The following dialog lets you either put in your MEX endpoint URL or discover it.

Notice that the discovered Name is the same as my defined Name in the Service Contract Attribute constructor argument for the Name. Here you can also configure advanced settings with the Advanced… Button. But we are ignoring the configuration possibilities for the proxy for now.

If you confirm the dialog with OK, the solution gets new part with ServiceReferences/ConnectedServices, where you will find your Proxy. To finally generate the proxy you need to use the UpdateServiceReference in the ContextMenu of the generated ServiceReference.

You can now proceed to use the proxy to invoke methods on the service like this:

var proxy = new MyNamespace.myServiceClient();
proxy.Connect();
string result = proxy.ReturnName();

Console.WriteLine(result); // prints ServiceImplementation
Console.ReadLine();
proxy.Disconnect();
proxy.Close(); // always remember to close the proxy when you are done

And this is how the auto generated proxy would look like:

//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Client.MyNamespace
{ 
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://mywcf/", ConfigurationName="MyNamespace.myService", SessionMode=System.ServiceModel.SessionMode.Required)]
public interface myService {

[System.ServiceModel.OperationContractAttribute(Action="http://mywcf/myService/Connect", ReplyAction="http://mywcf/myService/ConnectResponse")]
void Connect();

[System.ServiceModel.OperationContractAttribute(Action="http://mywcf/myService/Connect", ReplyAction="http://mywcf/myService/ConnectResponse")]
System.Threading.Tasks.Task ConnectAsync();

[System.ServiceModel.OperationContractAttribute(IsInitiating=false, Action="http://mywcf/myService/ReturnName", ReplyAction="http://mywcf/myService/ReturnNameResponse")]
string ReturnName();

[System.ServiceModel.OperationContractAttribute(IsInitiating=false, Action="http://mywcf/myService/ReturnName", ReplyAction="http://mywcf/myService/ReturnNameResponse")]
System.Threading.Tasks.Task<string> ReturnNameAsync();

[System.ServiceModel.OperationContractAttribute(IsTerminating=true, Action="http://mywcf/myService/Disconnect", ReplyAction="http://mywcf/myService/DisconnectResponse")]
void Disconnect();

[System.ServiceModel.OperationContractAttribute(IsTerminating=true, Action="http://mywcf/myService/Disconnect", ReplyAction="http://mywcf/myService/DisconnectResponse")]
System.Threading.Tasks.Task DisconnectAsync();
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public interface myServiceChannel : Client.MyNamespace.myService, System.ServiceModel.IClientChannel {
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class myServiceClient : System.ServiceModel.ClientBase<Client.MyNamespace.myService>, Client.MyNamespace.myService {

public myServiceClient() {
}

public myServiceClient(string endpointConfigurationName) : 
base(endpointConfigurationName) {
}

public myServiceClient(string endpointConfigurationName, string remoteAddress) : 
base(endpointConfigurationName, remoteAddress) {
}

public myServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
base(endpointConfigurationName, remoteAddress) {
}

public myServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
base(binding, remoteAddress) {
}

public void Connect() {
base.Channel.Connect();
}

public System.Threading.Tasks.Task ConnectAsync() {
return base.Channel.ConnectAsync();
}

public string ReturnName() {
return base.Channel.ReturnName();
}

public System.Threading.Tasks.Task<string> ReturnNameAsync() {
return base.Channel.ReturnNameAsync();
}

public void Disconnect() {
base.Channel.Disconnect();
}

public System.Threading.Tasks.Task DisconnectAsync() {
return base.Channel.DisconnectAsync();
}
}
}

 

Generate a Proxy with SVCUtil.exe

The next way to generate a proxy is to use the command line utility called SvcUtil.exe. This gives you the main advantage of using it in pre build steps of your build machine. The .exe can be found in C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools. Your path may deviate a little, just look for Microsoft SDKs in the program files

The SVCUtil.Exe employs numerous switches, like the /out switch to determine how you want to name your Proxy file. Most of these correspond to the configuration options that you can see in the dialog of Visual studio to generate a proxy.

In general you can use SvcUtil like so:

$> SvcUtil.exe "http://localhost:801/MEX" /out:Proxy.cs /directory:"Your_Directory_For_Proxy_cs"

 

Summary and Outlook to second page

We saw how you can generate a proxy and why you would do this. We explored how one can generate a proxy with Visual Studio and how one can go about creating a proxy with SvcUtil.exe. Also we looked a little bit at how WCF handles the remote calls to the service.

Categories: HowToWCF

0 Comments

Leave a Reply

Avatar placeholder