使用 UriTemplate 将枚举和自定义 类 传递给 WCF RESTful 服务

Passing Enum & Custom Classes to WCF RESTful service using UriTemplate

我已经使用以下 OperationContract

创建了一个 WCF 服务
[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 已被标记为 DataContract,成员

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

我已经阅读了Can I pass non-string to WCF RESTful service using UriTemplate?,但是在将枚举移至查询部分后它仍然无法正常工作。我错过了什么?

错误信息: 合约 'IFooProvider' 中的 GetFoo 操作有一个名为 'flags' 的路径变量,它没有类型 'string'。 UriTemplate 路径段的变量必须具有类型 'string'

对于第 3 个参数(传递 class),是否只能通过使用自定义 QueryStringConverter 来实现?

枚举在查询字符串中工作良好。对于自定义 class,是的,您需要使用查询字符串转换器。下面的代码显示了它是如何工作的一个例子。

如果在查询字符串中使用枚举仍有问题,请提供显示问题的 Short, Self-Contained, Compilable Example,我们应该能够提供帮助。

public class Whosebug_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();
    }
}