WCF Web Extensions
Posted on by Cosmin Vana
WCF Web Extensions 1.1
Nuget package which enhances WCF REST with functionalities like optional query parameters, http headers or multipart requests.
Roadmap:
- Version 1.0: Allow client to send optional query string parameters (available)
- Version 1.1: Allow client-server to use optional query string parameters in method parameters, instead of using WebOperationContext class, so that the parameters are at method level, not channel level (available)
- Version 1.2: Allow client to send custom HTTP headers
- Version 1.3: Allow multipart/form-data requests in both client and server in a typed manner
Installation: Install the following nuget package: VanaCosmin.WCF.WebExtensions
Usage
1. Define the service contract
[ServiceContract]
interface IWebExtendedTestService
{
[WebGet(UriTemplate = "")]
[OperationContract]
string GetWithOptionalParametersOnly([OptionalQueryStringParameters]NameValueCollection optionalParameters);
[WebGet(UriTemplate = "/{id}/{revisionNumber}/")]
[OperationContract]
string GetWithRouteElementsAndOptionalParameters(string id, string revisionNumber, [OptionalQueryStringParameters]NameValueCollection optionalParameters);
[WebGet(UriTemplate = "?formatType=xml")]
[OperationContract]
string GetWithFixedQueryStringAndOptionalParameters([OptionalQueryStringParameters]NameValueCollection optionalParameters);
[WebInvoke(UriTemplate = "", Method = "POST")]
[OperationContract]
string PostWithOptionalParametersOnly(Stream input, [OptionalQueryStringParameters]NameValueCollection optionalParameters);
}
Use OptionalQueryStringParameters attribute on the method parameter where you would like to receive all query parameters:
- OptionalQueryStringParameters attribute must be used only once for a method
- Only the last parameter of the method can be decorated with this attribute
- The type of the decorated parameter must be NameValueCollection
- Any query parameter will be forwarded there: e.g. on the template with ?formatType=xml, you will also get a formatType key with xml value
2. Implement the service class
To implement the service class, you simply need to implement the defined interface. On the service class you are not required to keep the OptionalQueryStringParameters attribute on the parameters decorated with it. It will not harm either if you keep it.
3. Start the service host
var service = new WebServiceHost(typeof(WebExtendedTestService));
service.AddServiceEndpoint(typeof(IWebExtendedTestService), new WebHttpBinding(), ServiceUri);
service.AddWebExtendedServiceBehavior();
service.Open();
return service;
Call the AddWebExtendedServiceBehavior() extension method from VanaCosmin.WCF.WebExtensions.ServerExtensions namespace in order to configure the service host to correctly process the OptionalQueryStringParameters attribute.
4. Call the service
using (var factory = new WebChannelFactory<IWebExtendedTestService>(new WebHttpBinding()))
{
factory.Endpoint.Address = new EndpointAddress(ServiceUri);
factory.AddWebExtendedClientBehavior();
using (var client = factory.CreateWebChannel())
{
NameValueCollection optionalParameters = new NameValueCollection();
optionalParameters.Add("a", "a");
optionalParameters.Add("b ", "&");
optionalParameters.Add("a=v", "=");
optionalParameters.Add("a5v", "/?=");
string result = client.Channel.GetWithOptionalParametersOnly(optionalParameters);
}
}
Call the AddWebExtendedClientBehavior() extension method from VanaCosmin.WCF.WebExtensions.ClientExtensions namespace in order to configure the client channel to correctly process the OptionalQueryStringParameters attribute. Note that the sample above uses CreateWebChannel() extension method from VanaCosmin.WCF.WebExtensions.ClientExtensions namespace, instead of directly calling CreateChannel() method. This is not required, however, using the extension method we provide will a disposable wrapper, which will also ensure the Channel is disposed when the wrapper is disposed.
5. Query parameters at channel level (version 1.0)
Sometimes you may want to send multiple requests using the same channel, and sending the same query parameters to all the requests. The way of adding query parameters at channel level introduced in version 1.0 is still available. There is no restriction into using one way or another, you can set up common parameters at channel level and send specific ones at method level:
using (var factory = new WebChannelFactory<IWebExtendedTestService>(new WebHttpBinding()))
{
factory.Endpoint.Address = new EndpointAddress(ServiceUri);
factory.AddWebExtendedClientBehavior();using (var client = factory.CreateWebChannel())
{
client.AddQueryParameter("last", "last");NameValueCollection optionalParameters = new NameValueCollection();
optionalParameters.Add("a", "a");
optionalParameters.Add("b ", "&");
optionalParameters.Add("a=v", "=");
optionalParameters.Add("a5v", "/?=");
string result = client.Channel.GetWithOptionalParametersOnly(optionalParameters);
}
}
Parameters added with AddQueryParameter extension method will be added at the end of the query string. Note that calling this method works on client object because it was created with CreateWebChannel() extension method. If you want to create the channel using the CreateChannel() method, you will have to cast the channel to IClientChannel interface.
(channel as IClientChannel).AddQueryParameter("key","value");