简体   繁体   中英

Error 400 when calling WCF JSONP web service method

I've created a WCF service that I'm attempting to use for a cross-domain call (using jQuery and JSONP). I've written the service and when I run it in the Visual Studio debugger and call it from a test page on my local PC it works fine. When I deploy the service to IIS7 on our server, it doesn't work. Looking at it with Fiddler, I see there's a 400 error coming back.

This is my first attempt at creating a WCF service and also my first attempt at JSONP, so it is highly possible I've missed something simple yet important.

I have 2 methods on this service, one really simple one (called GetData ) which just takes a string and returns it - I created this one just to test the basic service functionality (ie I can just put the URL into a browser and I get some json back) and it works OK.

The other, problematic, one (called GetMatter ) takes a couple of parameters, calls another (SOAP) web service to get some data and returns a Stream containing the call to my callback function. This then gets inserted into the calling page which displays the result.

The contract looks like this:

    [ServiceContract]
public interface IOracleService
{

    [OperationContract]
    [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "getData/{value}")]
    string GetData(string value);

    [OperationContract]
    [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "getMatter/{matterId}/{callback}")]
    Stream GetMatter(string matterId, string callback);


}

The implementation looks like this:

    public class OracleService : IOracleService
{
    public string GetData(string value)
    {
        return string.Format("You entered: {0}", value);
    }


    public Stream GetMatter(string matterId, string callback)
    {

        //call web service
        var serviceResult = <call to web service goes here>;

        //serialize data to json
        JavaScriptSerializer js = new JavaScriptSerializer();
        string jsonResult = js.Serialize(serviceResult.data);
        jsonResult = jsonResult.Substring(1, jsonResult.Length - 2);

        string result = callback + "(" + jsonResult + ");";

        return new MemoryStream(Encoding.UTF8.GetBytes(result));

    }

}

My simple Test.html page looks like this (for the purposes of this test, the js file is just stored on my local Q: drive):

    <html>

<head>
  <script src="./jquery-2.2.2.min.js" type="text/javascript"></script>
</head>

<body>

  <div id="output"></div>
  <div id="output2"></div>

  <script language="javascript">
    var url = "Q:\TestService.js";

    var script = document.createElement("script");
    script.setAttribute("src", url);
    script.setAttribute("type", "text/javascript");
    document.body.appendChild(script);
  </script>


</body>

</html>

TestService.js is as follows (note that Service.Legal is the namespace that OracleService is defined in, and MyServer is the name of the server that I've deployed the service to. When running in the debugger, MyServer is changed to "localhost:portnumber" and this works OK then)

    var url = "http://MyServer/Service.Legal.OracleWebService/OracleService.svc/GetData/1";

url += "?" + new Date().getTime().toString(); //append time to prevent caching


var script = document.createElement("script");
script.setAttribute("src", url);
script.setAttribute("type", "text/javascript");
document.body.appendChild(script);


function ServiceCallback(data) {
  console.log("got data: ");
  console.dir(data);

  var result = data;
  var date = new Date(parseInt(result.INVOICE_DATE.substr(6)));

  var output = "<ul>";
  output += "<li>INVOICE DATE: " + date + "</li>";
  output += "<li>TOTAL EXCL GST: " + result.TOTAL_EXCL_GST + "</li>";
  output += "<li>FEE ESTIMATE: " + result.FEE_ESTIMATE + "</li>";
  output += "</ul>";

  $("#output").html(output);

}

Finally, the web.config looks like:

 <configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> <authentication mode="Windows" /> </system.web> <system.serviceModel> <bindings> <webHttpBinding> <binding name="webHttpBinding" crossDomainScriptAccessEnabled="true"> <security mode="Transport"> <transport clientCredentialType="None" /> </security> </binding> </webHttpBinding> </bindings> <client /> <services> <service name="Service.Legal.OracleWebService.OracleService"> <endpoint address="" binding="webHttpBinding" contract="Service.Legal.OracleWebService.IOracleService" behaviorConfiguration="webBehaviour" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://MyServer/Service.Legal.OracleWebService/" /> </baseAddresses> </host> </service> </services> <behaviors> <endpointBehaviors> <behavior name="webBehaviour"> <webHttp/> </behavior> </endpointBehaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> <serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> </system.serviceModel> <system.webServer> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Headers" value="Content-Type, Accept" /> </customHeaders> </httpProtocol> <modules runAllManagedModulesForAllRequests="true" /> <directoryBrowse enabled="true" /> <httpErrors errorMode="Detailed" /> <validation validateIntegratedModeConfiguration="false" /> </system.webServer> </configuration> 

As I said above, when I run this service in the Visual Studio debugger, my html page runs the javascript in TestService.js, the javascript calls my service ( http://localhost:15021/OracleService.svc/GetMatter/matterId/ServiceCallback ) and I end up with the expected data being displayed on the page.

When I change that service url to point at the server ( http://MyServer/Service.Legal.OracleWebService/OracleService.svc/GetMatter/matterId/ServiceCallback ), I get a blank page and Fiddler shows the request giving error 400.

A basic test of the web service directly in the browser

http://MyServer/Service.Legal.OracleWebService/OracleService.svc/getData/1

does return the expected json data (although obviously IE just asks if I want to open or save "1.json", it doesn't display anything in the browser), so the service itself does appear to be accessible and working OK in IIS. There just seems to be something wrong with my GetMatter function or the way I'm calling it that is preventing it from working on the server.

Hmm OK never mind, I think I was looking at the wrong problem.

The 400 (bad request) error made me think the problem was with the call to my web service. But it seems the problem is actually happening on the server side when my web service tries to call the other web service. When I took out that call to the other web service, my service returned a 200 (success) instead. I'm going to work on the assumption that what I've got (as posted above) is OK, and the issue is something to do with the call to the other web service. Perhaps a firewall issue that is preventing the call going from my server to that server, while allowing it to go from my development machine to the same server.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM