C# RESTful WCF服务中标志枚举的默认值

C# RESTful WCF服务中标志枚举的默认值,c#,web-services,wcf,rest,enums,C#,Web Services,Wcf,Rest,Enums,WCF支持使用带有FlagsAttribute标记的枚举类型作为UriTemplate中的参数。像这样: [DataContract] [旗帜] 公共枚举选项枚举 { [委员] 无=0, [委员] MyOption1=1, [委员] MyOption2=2, [委员] MyOption3=4, [委员] MyOption4=8 } [服务合同] 公共接口MyServiceContract { [经营合同] [WebInvoke(Method=“GET”,UriTemplate=“resource

WCF支持使用带有
FlagsAttribute
标记的枚举类型作为
UriTemplate
中的参数。像这样:

[DataContract]
[旗帜]
公共枚举选项枚举
{
[委员]
无=0,
[委员]
MyOption1=1,
[委员]
MyOption2=2,
[委员]
MyOption3=4,
[委员]
MyOption4=8
}
[服务合同]
公共接口MyServiceContract
{
[经营合同]
[WebInvoke(Method=“GET”,UriTemplate=“resource?options={options}”)]
void MyOperation(选项枚举选项);
}
然后可以通过如下URL请求资源:

GET/resource?options=None

GET/resource?options=MyOption1

GET/resource?options=MyOption1,MyOption3

只要URL实际包含
options
参数的值,所有这些都能很好地工作。但是,如果我请求资源而没有在URL中指定值,则如下所示:

GET/resource

我收到一个异常,消息值不能为空。\r\n参数名称:值 以及以下堆栈跟踪:

at System.Enum.TryParseEnum(Type enumType, String value, Boolean ignoreCase, EnumResult& parseResult)
at System.Enum.Parse(Type enumType, String value, Boolean ignoreCase)
at System.ServiceModel.Dispatcher.QueryStringConverter.ConvertStringToValue(String parameter, Type parameterType)
at System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter.DeserializeRequest(Message message, Object[] parameters)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
显然,这是因为在本例中,
QueryStringConverter
null
传递到
Enum.Parse(…)
。因此,
MyServiceContract
的实现将不会执行

当然,对于
options
参数的类型,我可以直接切换到
string
,自己在服务实现中完成所有解析工作,但这并不是我真正想要的

是否有人知道一个干净的解决方案具有
选项枚举。如果URL不包含值,则不会将
传递到服务实现中(就像将
0
传递给
int
类型的省略参数一样)


我已经尝试过使用自定义的
TypeConverter
实现,但即使这样似乎也不起作用。查看
QueryStringConverter
的实现,它似乎总是试图自己转换
enum
类型。

好的,我找到了一个可重用的解决方案,不涉及切换到flags参数类型的
string
。不过,我希望有更简单的事情。无论如何,如果它能帮助其他人,就在这里

方法相对简单:

  • 将枚举包装为引用类型
  • 使用
    TypeConverter
    自定义将值从
    string
    转换为我们的标志枚举的过程,该过程由WCF的
    QueryStringConverter
    实现
//
///包装标志枚举值。
/// 
/// 
///该类旨在与
///并简单地装箱一个枚举。
///为了自定义枚举的WCF默认行为,这是必需的
///通过使用
/// .
/// 
/// 
///我们更喜欢这样,而不是使用1-Tuple()作为
///允许我们在类型参数上添加约束。还有,价值
///由包装的是只读的,这是我们不想要的
///这里,因为没有理由阻止[OperationContract]方法
///写这封信。
/// 
/// 
///枚举类型。必须归因于。
/// 
公共抽象类标志
其中TEnum:struct,i可转换
{
//使用静态c'tor在类型参数上添加运行时检查
//无法在编译时通过约束进行检查。
静态标志()
{
if(!typeof(TEnum).IsEnum)
{
抛出新的InvalidOperationException(“T不是枚举”);
}
如果(!typeof(TEnum).IsDefined(typeof(FlagsAttribute),false))
{
抛出新的InvalidOperationException(“T不是标志枚举”);
}
}
/// 
///枚举值。
/// 
公共财产价值
{
得到;
设置
}
}
/// 
///从
///串到。
/// 
/// 
/// 
///与…结合使用的。
///本实施的目的是:
///将null和空字符串转换为默认值(十位数)
///而不是抛出异常。这样,标志枚举(包装在
///的实例)可以用作
///RESTful WCF OperationContract方法中的可选参数。
/// 
/// 
///如果字符串值(由提供)
///为null或空,或者可以成功解析为枚举
///类型的值,则此实现将
///提供一个实例。因此,不存在任何问题
///需要检查一个类型化的值
///在OperationContract的实现中为空
///方法。
/// 
/// 
/// 
///一个子类。必须有一个默认的c'tor。
/// 
/// 
///枚举类型。必须归因于。
/// 
公共类标志转换器:类型转换器
其中TFlags:Flags,new()
其中TEnum:struct,i可转换
{
公共覆盖布尔CanConvertFrom(ITypeScriptorContext上下文,类型sourceType)
{
返回sourceType==typeof(字符串);
}
公共重写对象转换自(ITypeDescriptorContext上下文,
文化信息(文化,对象值)
{
if(string.IsNullOrEmpty((string)值))
{
//下面一行是Flags和FlagsConverter的定义
//全部关于:提供枚举的默认值(表示没有标志
//为null和空字符串而不是传递它
//进入Enum.Parse()(这将导致ArgumentException)。
返回新的TFlags{Value=default(TEnum)};
}
//否则,只需在Enum.Parse()上传递值,即不传递
//将任何进一步的更改添加到已实现的WCF默认行为中
//通过QueryStringConverter。
返回新的TFlags{Value=(TEnum)Enum.Parse(typeof(TEnum),(string)Value,true)};
}
}
这两个类现在可以用来解决这样的问题 (重用t