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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With