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.