Browse DevX
Sign up for e-mail newsletters from DevX


WCF Essentials—A Developer's Primer : Page 5

WCF is an SDK for building service-oriented applications on Windows, letting you use classic CLR programming constructs, such as classes and interfaces, to deploy and consume services. The programming model is declarative and largely attribute-driven.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Client-Side Programming
To invoke operations on the service, the client first needs to import the service contract to the client's native representation. This implies that the service needs to expose a standard way for clients to retrieve its metadata. This is done by having the service expose a metadata exchange (MEX) endpoint. A WCF-based service can expose a MEX endpoint automatically as long as the service registers at least one base address of TCP, HTTP, or IPC base address with the host.

If the client uses WCF, the common way of invoking operations is to use a proxy. The proxy is a CLR class that exposes a single CLR interface representing the service contract. Note that if the service supports several contracts (over at least as many endpoints), the client needs a proxy per contract type. The proxy provides the same operations as the service's contract, but also has additional methods for managing the proxy lifecycle and the connection to the service. The proxy completely encapsulates every aspect of the service: its location, its implementation technology and runtime platform, and the communication transport.

You can use Visual Studio 2005 to import the service metadata and generate a proxy. If the service is self-hosted, first launch the service and then select "Add Service Reference…" from the client project's context menu. If the service is hosted in IIS or the WAS, there is no need to pre-launch the service.

Interestingly enough, if the service is self-hosted in another project in the same solution as the client project, you can launch the host in Visual Studio 2005 and still add the reference, because unlike most project settings, this option is not disabled (see Figure 6). This brings up the Add Service Reference dialog box, where you need to supply the base address of the service (or a base address and a MEX URI) and the namespace to contain the proxy.

Figure 6. Generating a Proxy: You can generate a proxy using Visual Studio 2005.
Visual Studio 2005 uses the SvcUtil.exe command line utility, and you can use it yourself. The main reason is to use the numerous options offered by the SvcUtil switches. To use SvcUtil directly, provide it with the MEX address and, optionally, with a proxy filename. The default proxy file name is the name of the service-side class that implements the service. For example, when hosting the service MyService in IIS, simply run this command line:

SvcUtil http://localhost/MyService/MyService.svc /out:Proxy.cs

With self hosting, you are not limited to HTTP base addresses. Assume that the self-hosted service registers these base addresses:

http://localhost:8002 net.tcp://localhost:8003 net.pipe://localhost/MyPipe

The endpoint is the fusion of the address, contract, and binding.
Then launch the host and you can use any one of the following commands to generate the proxy:

SvcUtil http://localhost:8002/MEX /out:Proxy.cs SvcUtil http://localhost:8002/ /out:Proxy.cs SvcUtil net.tcp://localhost:8003/MEX /out:Proxy.cs SvcUtil net.pipe://localhost/MyPipe /MEX/out:Proxy.cs

For the service definition shown in Listing 1, SvcUtil generates the proxy shown in Listing 5.

The proxy class has no reference to the service-implementing class, only to the contract exposed by the service. The proxy can be used in conjunction with a client-side config file that provides the address and the binding or it can be used without a config file. Note that each proxy instance points at exactly one endpoint. The endpoint to interact with is provided to the proxy at construction time.

Administrative Client Configuration
The client needs to know where the service is located and use the same binding as its service, and, of course, import the service contract in the form of the proxy. In essence, this is exactly the same information captured in the service's endpoint. To reflect that, the client config file contains information about the target endpoints and even uses the same schema as the host.

For example, Listing 6 shows the client configuration file required to interact with a service whose host is configured according to Listing 2. Note that the contract type (and namespace) in the client config file is the imported type (and namespace, if any) generated by SvcUtil, not the service type and namespace. The client config file may list as many endpoints as the service supports and the client may use any one of them to interact with the service. Listing 7 shows the client config file that matches the host config file shown in Listing 3.

By default, SvcUtil also auto-generates a client-side config file called output.config. You can specify a config file name using the /config switch:

SvcUtil http://localhost:8002/MyService/MEX /out:Proxy.cs /config:App.Config

And you can suppress generating the config file using the /noconfig switch:

Figure 7: SvcConfigEditor is used to edit both host and client config files.

SvcUtil http://localhost:8002/MyService/MEX /out:Proxy.cs /noconfig

To support in-proc hosting, the application config file should list both the service and the client sections, as shown in Listing 8. Note the use of NetNamedPipeBinding for in-proc invocation.

WCF provides a config file editor called SvcConfigEditor.exe that can edit both host and client configuration files (see Figure 7). At the time of this writing, SvcConfigEditor generates messy unreadable config files, so until that is amended, you should edit the files manually.

Creating and Using the Proxy
The SvcUtil-generated proxy class derives from the class ClientBase<T>, defined as:

public class ClientBase<T> : IDisposable { protected ClientBase(string endpointConfigurationName); protected ClientBase( Binding binding, EndpointAddress remoteAddress); public void Close(); public void Dispose(); protected T InnerProxy{get;} //Additional members }

The InnerProxy property is of the type of the contract the client needs to consume, and the SvcUtil-generated sub class of ClientBase<T> simply delegates it to the method call (see Listing 5). The client needs to instantiate a proxy object and provide the constructor with endpoint information—either the endpoint section name from the config file (see Listing 6) or the endpoint address and binding objects when not using a config file. The client can then use the proxy methods to call the service, and when the client is done, the client needs to close the proxy instance:

MyContractProxy proxy = new MyContractProxy("MyEndpoint"); proxy.MyMethod(); proxy.Close();

Closing the proxy terminates the session with the service and closes the connection. Alternatively, you can use the Dispose() method of the proxy to close it. The advantage of the Dispose() method is that you can use the using statement to call it even in the face of exceptions:

using(MyContractProxy proxy = new MyContractProxy("MyEndpoint")) { proxy.MyMethod(); }

At most, one endpoint per contract type in the client config file can be designated as a default endpoint. The default endpoint is an endpoint section without a name tag or with an empty name (""):

<system.serviceModel> <client> <endpoint ... contract="IMyContract" /> <endpoint name="OtherEndpoint" ... contract="IMyContract" /> </client> </system.serviceModel>

A default endpoint is just a nicety; when creating a proxy targeting the default endpoint, use the default constructor of the proxy to make it use the default endpoint:

MyContractProxy proxy = new MyContractProxy(); proxy.MyMethod(); proxy.Close();

Programmatic Client Configuration
Instead of relying on a config file, the client can programmatically construct the endpoint and provide that to the proxy constructor. Listing 9 demonstrates this technique, showing the code equivalent to Listing 6 targeting the service in Listing 2. Programmatic configuration is useful when the endpoint decision is either completely dynamic, when it is taken at runtime based on the current input or conditions, or when the decision is static and never changes, in which case, you might as well hard code it.

Thanks for your registration, follow us on our social networks to keep up-to-date