Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Consuming REST Service with WCF - Optional Querystring Parameters?

Tags:

c#

.net

wcf

I am having problems trying to consume a simple service using WCF. Everything has gone well so far except when coming to implement optional query string parameters. The interface looks a bit like this:

[ServiceContract]
[XmlSerializerFormat]
public interface IApi
{
    [OperationContract]
    [WebGet(UriTemplate = "/url/{param}?top={top}&first={first}")]
    object GetStuff(string param, int top, DateTime first);
}

Then this is consumed by creating a class that inherits ClientBase<IApi>. I tried a few ways to make the parameters optional:

1) Make the parameters nullable

This did not work. I get a message from the QueryStringConverter like another question has asked: Can a WCF service contract have a nullable input parameter?

2) One Parameter at the end of the URL

So, I thought about changing the UriTemplate to be more generic, building the query string and passing it through as a parameter. This didn't seem to work either, as the value passed in gets encoded such that it is not recognised as a querystring by the server.

Example:

[WebGet(UriTemplate = "/url/{query}")]

3) Hackish Solution

The only way I found so far of getting this to work is to change all the parameters to strings, and NULL's seem to be allowed here.

Example:

[WebGet(UriTemplate = "/url/{param}?top={top}&first={first}")]
object GetStuff(string param, string top, string first);

The consumption of this interface still accepts the correct variable type, but ToString is used. Thes query string parameters still appear in the actual request.

So, is there a way when consuming a REST service using WCF, to make the query string parameters optional?

UPDATE - How it was fixed

The advice to create a service behaviour was taken. This inherits from WebHttpBehaviour. It looks as follows:

public class Api : ClientBase<IApi>
{
    public Api() : base("Binding")
    {
        Endpoint.Behaviors.Add(new NullableWebHttpBehavior());
    }
}

The NullableWebHttpBehavior can be found at the following Stackoverflow question: Can a WCF service contract have a nullable input parameter?. The only problem was, ConvertValueToString wasn't overloaded, so I whipped a quick one up:

    public override string ConvertValueToString(object parameter, Type parameterType)
    {
        var underlyingType = Nullable.GetUnderlyingType(parameterType);

        // Handle nullable types
        if (underlyingType != null)
        {
            var asString = parameter.ToString();

            if (string.IsNullOrEmpty(asString))
            {
                return null;
            }

            return base.ConvertValueToString(parameter, underlyingType);
        }

        return base.ConvertValueToString(parameter, parameterType);
    }

This may not be perfect, but it seems to work as intended.

like image 894
Hux Avatar asked May 10 '12 18:05

Hux


1 Answers

Your option 1) can work for a WCF client because the WebHttpBehavior can be applied to a ClientBase (or ChannelFactory) derived class as shown in this SO question & answer. Just combine the code you reference in 1) with the configuration shown in the capturing 500 responses question and it show work.

like image 159
Sixto Saez Avatar answered Sep 23 '22 06:09

Sixto Saez