WCF Complex JSON INPUT Error (not convertible by QueryStringConverter)

I don't believe you're allowed to pass complex types on the query string using WCF this way. See this response from a Microsoft tech in the ASP.NET forums - it's similar to your situation.

Based on how you've stubbed out your service method, it seems like a more appropriate verb to use would be POST or PUT, and you could put your CompositeType payload in the request body. But I'm guessing as to your intention.

I was able to make your code work and still use a GET by changing the query string type from CompositeType to String and then deserializing the JSON string into a CompositeType by using the ASP.NET JavaScriptSerializer class. (You can use your favorite JSON helper class here -- I'm partial to JSON.NET, but I also hear FlexJson is very good, too.)

I didn't touch your web.config (except to make it work in my local test app). My only change was in the service method signature and the implementation of the service method.

[ServiceContract]
public interface IService1
{

    [OperationContract]
    [WebGet(UriTemplate = "GetDataUsingDataContract?composite={composite}",
        BodyStyle = WebMessageBodyStyle.Wrapped,
        RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    CompositeType GetDataUsingDataContract(String composite);

    // TODO: Add your service operations here
}


public class Service1 : IService1
{
    public CompositeType GetDataUsingDataContract(String composite)
    {
        //use the JavaScriptSerializer to convert the string to a CompositeType instance
        JavaScriptSerializer jscript = new JavaScriptSerializer();
        CompositeType newComp = jscript.Deserialize<CompositeType>(composite);
        newComp.StringValue += " NEW!";
        return newComp;
    }

}

I hope this helps. Let me know if you have other questions with this.


[NEW ANSWER (2019]

In case somebody is still searching for this (I just did, and I figured out a good solution).

In contract file:

[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, UriTemplate = "TestBlockHeight?blockHeight={blockHeight}")]
Task<string> TestBlockHeight(BlockHeight blockHeight);

In service file:

public async Task<string> TestBlockHeight(BlockHeight blockHeight)
{
    return await Task.FromResult($"Called TestBlockHeight with parameter {blockHeight}");
}

My custom BlockHeight type class:

[TypeConverter(typeof(MyBlockHeightConverter))]
public class BlockHeight : IComparable<ulong>
{
    private ulong value;

    public BlockHeight(ulong blockHeight)
    {
        value = blockHeight;
    }
}

And the custom TypeConverter class that I needed to create:

public class MyBlockHeightConverter : TypeConverter
{
    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if(destinationType == typeof(string) && value is BlockHeight blockHeight)
        {
            return blockHeight.ToString();
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if(value is string str)
        {
            return new BlockHeight(ulong.Parse(str));
        }
        return base.ConvertFrom(context, culture, value);
    }

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        if(sourceType == typeof(string))
        {
            return true;
        }
        return base.CanConvertFrom(context, sourceType);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        if (destinationType == typeof(string))
        {
            return true;
        }
        return base.CanConvertTo(context, destinationType);
    }
}

This works because WCF uses a QueryStringConverter to serialize url parameters, and only specific types are allowed. One of these types is an arbitrary type which is decorated with TypeConverterAttribute. More info here: https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.dispatcher.querystringconverter?view=netframework-4.8

Tags:

Wcf

Json