2

I have created a WCF Service with the following OperationContract

[WebGet(UriTemplate = "/foo?id={Id}&flags={flags}&filter={filter}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Wrapped)]
[OperationContract]
DataTable GetFoo(string id, FlaggedEnum flags, SomeClass filter = null);

FlaggedEnum have been marked as DataContract with members

[DataContract]
[Flags]
public enum FlaggedEnum
{
    [EnumMember]
    Book = 1,
    [EnumMember]
    Product = 2,
    [EnumMember]
    TenorGroup = 4,
    [EnumMember]
    Tenor = 8,
    [EnumMember]
    Trade = 16
}

I have read Can I pass non-string to WCF RESTful service using UriTemplate?, yet somehow it still does not work after the enum has been moved to the query part. What have I missed out?

Error Message: Operation GetFoo in contract 'IFooProvider' has a path variable named 'flags' which does not have type 'string'. Variables for UriTemplate path segments must have type 'string'

And for the 3rd parameter (passing a class), is it only achievable by using a custom QueryStringConverter?

Community
  • 1
  • 1
Higgs
  • 550
  • 5
  • 18

1 Answers1

4

Enums work fine in query strings. For the custom class, yes, you need to use a query string converter. The code below shows how one example of it working.

If you still have problems with using enums in the query string, please provide a Short, Self-Contained, Compilable Example that shows the problem, and we should be able to help.

public class StackOverflow_31184719
{
    [ServiceContract]
    public interface ITest
    {
        [WebGet(UriTemplate = "/foo?id={Id}&flags={flags}&filter={filter}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Wrapped)]
        [OperationContract]
        string GetFoo(string id, FlaggedEnum flags, SomeClass filter = null);
    }
    [Flags]
    public enum FlaggedEnum
    {
        [EnumMember]
        Book = 1,
        [EnumMember]
        Product = 2,
        [EnumMember]
        TenorGroup = 4,
        [EnumMember]
        Tenor = 8,
        [EnumMember]
        Trade = 16
    }
    public class SomeClass
    {
        public string SomeProperty { get; set; }
    }
    public class MyWebHttpBehavior : WebHttpBehavior
    {
        protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
        {
            return new MyConverter(base.GetQueryStringConverter(operationDescription));
        }

        class MyConverter : QueryStringConverter
        {
            QueryStringConverter inner;
            public MyConverter(QueryStringConverter inner)
            {
                this.inner = inner;
            }

            public override bool CanConvert(Type type)
            {
                return type == typeof(SomeClass) || this.inner.CanConvert(type);
            }

            public override object ConvertStringToValue(string parameter, Type parameterType)
            {
                if (parameterType == typeof(SomeClass))
                {
                    return new SomeClass { SomeProperty = parameter };
                }
                else
                {
                    return base.ConvertStringToValue(parameter, parameterType);
                }
            }
        }
    }
    public class Service : ITest
    {
        public string GetFoo(string id, FlaggedEnum flags, SomeClass filter = null)
        {
            return string.Format("{0} - {1} - {2}", id, flags, filter == null ? "<<NULL>>" : filter.SomeProperty);
        }
    }
    public static void Main()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "");
        endpoint.Behaviors.Add(new MyWebHttpBehavior());
        host.Open();
        Console.WriteLine("Host opened");

        WebClient c = new WebClient();
        Console.WriteLine(c.DownloadString(baseAddress + "/foo?id=MyId&flags=Book,Product&filter=MyFilter"));

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
  • thanks for providing the example for a class. indeed it can do enum conversion by default, seems my project just didn't get rebuilt properly – Higgs Jul 03 '15 at 10:31