0

My webservice uses (msdn) to expose a REST interface. Some methods accept an enum as parameter; e.g.:

[ServiceContract]
public partial interface IStrangeEnumDemo
{        
    [OperationContract]
    [WebGet(UriTemplate = "DefaultEnumName?q={val}")]
    string DefaultEnumName(DefaultNumberEnum val);
}

with DefaultNumberEnum being:

// Note values in this Enum are not annotated with [System.RunTime.Serialization.EnumMember] or [System.Runtim.Serialization.DataContract], both are not needed
public enum DefaultNumberEnum
{
    APPLE,
    PEAR,
    BANANA
}

The operation's implementation is:

public partial class StrangeEnumDemo : IStrangeEnumDemo
{
    public string DefaultEnumName(DefaultNumberEnum val)
    {
        return $"Fruit: {val.ToString()}";
    }
}

According to the MSDN documentation of QueryStringConverter, Ohad Schneider's answer to Can I pass non-string to WCF RESTful service using UriTemplate?, and Carlos Figueira's MSDN blog the QueryStringConverter should convert enum names to their value.

Calling the webservice via:

http://localhost:16772/StrangeEnumDemo.svc/DefaultEnumName?q=PEAR

results in the response1 as expected:

"Fruit: PEAR"

Another enum, that I would like to use as parameter, is backed by a byte; e.g.:

public enum ByteEnum: byte
{
    ALIGATOR,
    BEAR,
    ZEBRA
}

The operation declaration and implementation are almost identical to the ones of DefaultNumber enum:

[ServiceContract]
public partial interface IStrangeEnumDemo
{
    [OperationContract]
    [WebGet(UriTemplate = "ByteEnumName?q={val}")]
    string ByteEnumName(ByteEnum val);
}

and

public partial class StrangeEnumDemo : IStrangeEnumDemo
{
    public string ByteEnumName(ByteEnum val)
    {
        return $"Animal: {val.ToString()}";
    }
}

However, when calling:

http://localhost:16772/StrangeEnumDemo.svc/ByteEnumName?q=BEAR

I receive:

<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
    <Code>
    <Value>Receiver</Value>
    <Subcode>
        <Value xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault</Value>
    </Subcode>
    </Code>
    <Reason>
    <Text xml:lang="nl-NL">Input string was not in a correct format.</Text>
    </Reason>
    <Detail>
    <ExceptionDetail xmlns="http://schemas.datacontract.org/2004/07/System.ServiceModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <HelpLink i:nil="true"/>
        <InnerException i:nil="true"/>
        <Message>Input string was not in a correct format.</Message>
        <StackTrace>   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer&amp; number, NumberFormatInfo info, Boolean parseDecimal)&#xD;
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)&#xD;
   at System.Byte.Parse(String s, NumberStyles style, NumberFormatInfo info)&#xD;
   at System.ServiceModel.Dispatcher.QueryStringConverter.ConvertStringToValue(String parameter, Type parameterType)&#xD;
   at System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter.DeserializeRequest(Message message, Object[] parameters)&#xD;
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</StackTrace>
        <Type>System.FormatException</Type>
    </ExceptionDetail>
    </Detail>
</Fault>

For completeness, this is my service.svc:

<%@ ServiceHost Language="C#" Debug="true" Service="StrangeEnumBehavior.StrangeEnumDemo" CodeBehind="StrangeEnumDemo.svc.cs" %>

And this is my web.config:

<?xml version="1.0"?>
<configuration>
    <appSettings>
        <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
    </appSettings>
    <!--
        For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367.

        The following attributes can be set on the <httpRuntime> tag.
            <system.Web>
                <httpRuntime targetFramework="4.7" />
            </system.Web>
    -->
    <system.web>
        <compilation debug="true" targetFramework="4.7"/>
        <httpRuntime targetFramework="4.7"/>
    </system.web>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior>
                    <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
                    <serviceDebug includeExceptionDetailInFaults="true"/>
                </behavior>
            </serviceBehaviors>
            <endpointBehaviors>
                <behavior>
                    <webHttp automaticFormatSelectionEnabled="true" faultExceptionEnabled="true"/>
                </behavior>
            </endpointBehaviors>
        </behaviors>
        <protocolMapping>
            <add binding="webHttpBinding" scheme="http"/>
        </protocolMapping>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="false"/>
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
        <!--
                To browse web app root directory during debugging, set the value below to true.
                Set to false before deployment to avoid disclosing web app folder information.
            -->
        <directoryBrowse enabled="true"/>
    </system.webServer>
</configuration>

Is there a way to have QueryStringConverter parse names of values of byte enums the same as it parses enums with implicit backing storage?

An solution I came up with is to use a different enum with implicit backing storage and use that a a data contract and convert manually (or use data contract surrogate to have automatic conversion); but I would rather not duplicate the enum.

The original enum has to be stored as a byte.


1I use the header Accept: application/json to have the service return JSON data.

Kasper van den Berg
  • 8,951
  • 4
  • 48
  • 70
  • It also seems that in your error message, the values are supposed to be bytes (there is a `Byte.Parse` error). Does it work if you would specify it like [this](https://msdn.microsoft.com/en-us/library/system.runtime.serialization.enummemberattribute(v=vs.110).aspx) using the `EnumMemberAttribute` – Icepickle Jun 20 '17 at 13:35
  • Annotating with `DataContractAttribute` and `EnumMemberAttribute` has the same effect as without the attributes. – Kasper van den Berg Jun 22 '17 at 08:54

0 Answers0