问题 WCF复杂JSON INPUT错误(不能由QueryStringConverter转换)


我有问题解决复杂JSON作为我的WCF服务中的参数。

在Visual Studio 2008 SP1中使用Microsoft.Net 3.5 SP1

使用以下合同:

[ServiceContract]
public interface IService1
{

    [OperationContract]
    [WebGet(UriTemplate="GetDataUsingDataContract?composite={composite}", 
        BodyStyle=WebMessageBodyStyle.Wrapped, 
        RequestFormat=WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    CompositeType GetDataUsingDataContract(CompositeType composite);

    // TODO: Add your service operations here
}

// Use a data contract as illustrated in the sample below to add composite types to service operations
[DataContract]
public class CompositeType
{
    string boolValue = "true";
    string stringValue = "Hello ";

    [DataMember]
    public string BoolValue
    {
        get { return boolValue; }
        set { boolValue = value; }
    }

    [DataMember]
    public string StringValue
    {
        get { return stringValue; }
        set { stringValue = value; }
    }
}

使用以下URL:

http://localhost:1122/Service1.svc/GetDataUsingDataContract?composite={"BoolValue":"True","StringValue":"Hello"}

使用Enpoint配置:

<system.serviceModel>
    <services>
        <service name="WebHTTPBindingExample.Service1" behaviorConfiguration="WebHTTPBindingExample.Service1Behavior">
            <host>
                <baseAddresses>
                    <add baseAddress="http://localhost:8731/Design_Time_Addresses/WebHTTPBindingExample/Service1/"/>
                </baseAddresses>
            </host>
            <!-- Service Endpoints -->
            <!-- Unless fully qualified, address is relative to base address supplied above -->
            <!--<endpoint address="" binding="wsHttpBinding" contract="WebHTTPBindingExample.IService1">
                --><!-- 
      Upon deployment, the following identity element should be removed or replaced to reflect the 
      identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
      automatically.
  --><!--
                <identity>
                    <dns value="localhost"/>
                </identity>
            </endpoint>-->
            <endpoint address="Web" behaviorConfiguration="ChatAspNetAjaxBehavior" binding="webHttpBinding" name="ajaxEndpoint" contract="WebHTTPBindingExample.IService1"/>
            <!-- Metadata Endpoints -->
            <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
            <!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="WebHTTPBindingExample.Service1Behavior">
                <!-- To avoid disclosing metadata information, 
  set the value below to false and remove the metadata endpoint above before deployment -->
                <serviceMetadata httpGetEnabled="True"/>
                <!-- 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="False"/>
            </behavior>
        </serviceBehaviors>
        <endpointBehaviors>
            <behavior name="ChatAspNetAjaxBehavior">
                <webHttp/>
            </behavior>
        </endpointBehaviors>
    </behaviors>
</system.serviceModel>

我得到了以下错误:

Operation 'GetDataUsingDataContract' in contract 'IService1' has a query variable named 'composite' of type 'WebHTTPBindingExample.CompositeType', but type 'WebHTTPBindingExample.CompositeType' is not convertible by 'QueryStringConverter'.  Variables for UriTemplate query values must have types that can be converted by 'QueryStringConverter'.

11965
2018-03-09 05:16


起源



答案:


我不相信你可以通过这种方式使用WCF在查询字符串上传递复杂类型。看到 这个回应 来自ASP.NET论坛中的Microsoft技术 - 它与您的情况类似。

根据你如何删除你的服务方法,似乎一个更合适的动词使用POST或PUT,你可以把你的 CompositeType 请求正文中的有效负载。但我猜你的意图。

我能够使您的代码工作,并通过更改查询字符串类型仍然使用GET CompositeType 至 String 然后将JSON字符串反序列化为 CompositeType 通过使用ASP.NET JavaScriptSerializer 类。 (你可以在这里使用你最喜欢的JSON助手类 - 我很偏爱 JSON.NET,但我也听到了 FlexJson 非常好。)

我没有触摸你的web.config(除了让它在我的本地测试应用程序中工作)。我唯一的改变是服务方法签名和服务方法的实现。

[ServiceContract]
public interface IService1
{

    [OperationContract]
    [WebGet(UriTemplate = "GetDataUsingDataContract?composite={composite}",
        BodyStyle = WebMessageBodyStyle.Wrapped,
        RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    CompositeType GetDataUsingDataContract(String composite);

    // TODO: Add your service operations here
}


public class Service1 : IService1
{
    public CompositeType GetDataUsingDataContract(String composite)
    {
        //use the JavaScriptSerializer to convert the string to a CompositeType instance
        JavaScriptSerializer jscript = new JavaScriptSerializer();
        CompositeType newComp = jscript.Deserialize<CompositeType>(composite);
        newComp.StringValue += " NEW!";
        return newComp;
    }

}

我希望这有帮助。如果您对此有其他疑问,请与我们联系。


12
2018-03-09 15:01



大卫感谢你花在这上面的所有时间,你帮助了我!我决定使用POST。我有点惊讶它不会在GET上工作,因为它在这里显示了一个例子: msdn.microsoft.com/en-us/library/bb412170%28v=VS.90%29.aspx。请参阅URL中的JSON部分。再次感谢大卫的时间。 - Boden
很高兴我可以帮忙。我认为你链接到的文章的关键是,如果你使用ASP.NET AJAX(我认为你使用),复杂的类型可以在查询字符串中 enableWebScript 在您的端点行为而不是 webHttp)。我认为你最好不要使用ASP.NET AJAX,因为在更纯粹的客户端框架(如jQuery)中,这会在MSFT中失去支持。坚持使用webHttp并将这些类型的请求作为POST和PUT处理更加纯粹。这只是我的意见,因为这是值得的。 :) 祝你好运!! - David Hoerster


答案:


我不相信你可以通过这种方式使用WCF在查询字符串上传递复杂类型。看到 这个回应 来自ASP.NET论坛中的Microsoft技术 - 它与您的情况类似。

根据你如何删除你的服务方法,似乎一个更合适的动词使用POST或PUT,你可以把你的 CompositeType 请求正文中的有效负载。但我猜你的意图。

我能够使您的代码工作,并通过更改查询字符串类型仍然使用GET CompositeType 至 String 然后将JSON字符串反序列化为 CompositeType 通过使用ASP.NET JavaScriptSerializer 类。 (你可以在这里使用你最喜欢的JSON助手类 - 我很偏爱 JSON.NET,但我也听到了 FlexJson 非常好。)

我没有触摸你的web.config(除了让它在我的本地测试应用程序中工作)。我唯一的改变是服务方法签名和服务方法的实现。

[ServiceContract]
public interface IService1
{

    [OperationContract]
    [WebGet(UriTemplate = "GetDataUsingDataContract?composite={composite}",
        BodyStyle = WebMessageBodyStyle.Wrapped,
        RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    CompositeType GetDataUsingDataContract(String composite);

    // TODO: Add your service operations here
}


public class Service1 : IService1
{
    public CompositeType GetDataUsingDataContract(String composite)
    {
        //use the JavaScriptSerializer to convert the string to a CompositeType instance
        JavaScriptSerializer jscript = new JavaScriptSerializer();
        CompositeType newComp = jscript.Deserialize<CompositeType>(composite);
        newComp.StringValue += " NEW!";
        return newComp;
    }

}

我希望这有帮助。如果您对此有其他疑问,请与我们联系。


12
2018-03-09 15:01



大卫感谢你花在这上面的所有时间,你帮助了我!我决定使用POST。我有点惊讶它不会在GET上工作,因为它在这里显示了一个例子: msdn.microsoft.com/en-us/library/bb412170%28v=VS.90%29.aspx。请参阅URL中的JSON部分。再次感谢大卫的时间。 - Boden
很高兴我可以帮忙。我认为你链接到的文章的关键是,如果你使用ASP.NET AJAX(我认为你使用),复杂的类型可以在查询字符串中 enableWebScript 在您的端点行为而不是 webHttp)。我认为你最好不要使用ASP.NET AJAX,因为在更纯粹的客户端框架(如jQuery)中,这会在MSFT中失去支持。坚持使用webHttp并将这些类型的请求作为POST和PUT处理更加纯粹。这只是我的意见,因为这是值得的。 :) 祝你好运!! - David Hoerster


David Hoerster - 您的链接是从2009年开始的,今天无效。

如果您查看以下文档: http://msdn.microsoft.com/en-us/library/bb412179(v=vs.90).aspx

你可以看到,为了调用

 MyOperation(int number,Person p)

你可以做以下事情:

http://example.com/myservice.svc/MyOperation?number=7&p={"name":"John","age":42}

戴维斯的建议或许简化了编程方面的一些事情,但它违反了所有关于记录自己的方法签名的REST规则。

此外,请确保您的绑定是webHttpBinding以从SOAP转换为REST。


0
2018-03-20 22:58



我很喜欢它,但我没有在你提供的链接上看到它... - BlazingFrog
能否请您提供相关示例的确切链接? - Sankalp
这是更合适的链接,但是,它也说“JSON不能在非ASPP.NET AJAX端点上的URL中使用”,所以很可能你仍然无法在WebGet中使用JSON: msdn.microsoft.com/en-us/library/bb412170(v=vs.100).aspx - demp


只需使用不带参数的WebGet属性:

[ServiceContract]
public interface IService1
{
    [OperationContract]
    [WebGet]
    CompositeType GetDataUsingDataContract(CompositeType composite);
}

在Web.config上,使用enableWebScript和webHttpBinding:

<configuration>
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="jsonBehavior">
          <enableWebScript />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service name="Application.Service1">
        <endpoint address="json" behaviorConfiguration="jsonBehavior" binding="webHttpBinding" contract="Application.IService1" />
        <endpoint address="soap" binding="basicHttpBinding" contract="Application.IService1" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

然后你可以像这样调用你的JSON REST:

http://localhost:29075/Service1.svc/json/GetDatausingDataContract?composite={ "BoolValue": true, "StringValue":  "Akira"}

注意:使用此配置,您可以同时使用JSON REST和SOAP。


0
2017-09-15 21:09