使用WCF webHttp绑定,是否可以传递任意查询字符串参数?

时间:2016-03-01 17:52:16

标签: wcf rest

情景:

  • 我想调用REST服务
  • 我想使用WCF webHttpBinding来调用服务
  • 该服务接受GET请求,例如:

    GET /endpoint/{resourcename}/?arg1=a&arg2=b&...

  • 查询字符串参数可以根据resourcename而变化。我不想在具有特定UriTemplate设置的界面中创建多个方法。

  • 作为额外的奖励,可以多次指定查询字符串参数,即GET /SomeResource/?a=1&a=2&a=3是有效请求。
  • 我想要的是下面的合同,WCF webHttpBinding可以处理吗?

示例:

[WebGet(UriTemplate="/{resourcename}/???")]
[OperationContract]
Whatever DoTheThing(string resourcename, Dictionary<string, string> queryStringArgs)

2 个答案:

答案 0 :(得分:3)

如果您可以接受这样的事实,即在调用方法时未填充tableView,而是作为实施的第一步,这将有效:

queryStringArgs

这是界面注释的方式:

public string GetData(string value)
{
    var utm = WebOperationContext.Current.IncomingRequest.UriTemplateMatch;
    var queryStringArgs = new Dictionary<string, string>();
    foreach(var query in utm.QueryParameters.AllKeys)
    {
        queryStringArgs.Add(query, utm.QueryParameters[query]);
    }

    return string.Format("You entered: {0} {1}", value, queryStringArgs);
}

当您抓住当前WebOperationContext时,您可以访问[OperationContract] [WebGet(UriTemplate = "/GetData/{value}")] string GetData(string value); 上的UrlTemplateMatch媒体资源。

通过迭代IncomingRequest(NameValueCollection)的原始内容,您可以以自定义方式处理每个内容,其中一个可以将它们添加到字典中。

答案 1 :(得分:1)

您可以编写一个自定义QueryStringConverter来接收所有查询字符串参数,并可以根据需要对其进行处理。这是最灵活的方式,但需要一些工作。

1。首先创建自定义QueryStringConverter课程,如下所示:

public class CustomQueryStringConverter : System.ServiceModel.Dispatcher.QueryStringConverter
{
    public override bool CanConvert(Type type)
    {
        if (type == typeof(Dictionary<string, string>))
            return true;
        // ELSE:
        return base.CanConvert(type);
    }

    public override object ConvertStringToValue(string parameter, Type parameterType)
    {
        if (parameterType != typeof(Dictionary<string, string>))
            return base.ConvertStringToValue(parameter, parameterType);
        // ELSE (the type is Dictionary<string, string>)
        if (parameter == null)
            return new Dictionary<string, string>();

        return JsonConvert.DeserializeObject<Dictionary<string, string>>(parameter);
    }
}

2。其次,要在您的终端中使用此查询字符串转换器,您需要创建自定义WebHttpBehavior并覆盖GetQueryStringConverter以返回自定义查询字符串转换器,如下:

public sealed class CustomWebHttpBehavior : WebHttpBehavior
{
    public CustomWebHttpBehavior()
    {
        // you can set default values for these properties here if you need to:
        DefaultOutgoingResponseFormat = WebMessageFormat.Json;
        AutomaticFormatSelectionEnabled = true;
        DefaultBodyStyle = WebMessageBodyStyle.Bare;
        HelpEnabled = true;
    }

    protected override System.ServiceModel.Dispatcher.QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
    {
        return new CustomQueryStringConverter();
    }
}

3. 第三步是创建BehaviorExtensionElement类,以便能够在wcf配置文件中注册自定义行为,如下所示:

public class CustomWebHttpBehaviorElement : BehaviorExtensionElement
{

    public override System.Type BehaviorType
    {
        get { return typeof(CustomWebHttpBehavior); }
    }

    protected override object CreateBehavior()
    {
        return new CustomWebHttpBehavior();
    }
}

4. 作为最后一步,您应该在wcf项目的web.config文件中注册自定义行为,如下所示:

<system.serviceModel>
    ...

    <extensions>
        <behaviorExtensions>
            <add name="customWebHttpBehaviorElement" type="Your.Namespace.CustomWebHttpBehaviorElement, Your.Assembly" />
        </behaviorExtensions>
    </extensions>
    ...

    <behaviors>
        <endpointBehaviors>
            <behavior name="RestServiceEndpointBehavior">
                <customWebHttpBehaviorElement />
            </behavior>
        </endpointBehaviors>
    </behaviors>
    ...

</system.serviceModel>

执行这些(不容易)步骤后,如果您使用RestServiceEndpointBehavior作为端点的行为配置,则自定义查询字符串转换器将适用于该端点的所有请求。

编辑:我忘记提到的一点是你需要将你的查询字符串作为json对象传递:/SomeResource/?args={"a":1,"b"=2,"c"=3}这意味着你的查询字符串只有1个参数(args)包含您的实际参数(a,b,c)。

编辑2: 您的服务方法如下所示:

    public string DoTheThing(Dictionary<string, string> args)
    {
        var resourceName = "";
        if(args.ContainsKey("resourceName"))
            resourceName = args["resourceName"];
        return string.Format("You entered: {0}", args);     
    }

合同就是这样的:

    [WebInvoke(Method = "GET")]
    [OperationContract]
    string DoTheThing(Dictionary<string, string> args);

请注意,查询字符串中的参数名称"args"应与服务方法中的参数名称匹配,否则无法正常工作。

此解决方案的好处是您不需要为每种服务方法使用UriTemplate,缺点是您应该将查询字符串转换为json格式,当然您也会丢失重复参数选项。

希望这有帮助。