Search code examples
asp.net-mvcwcfc#-4.0rest

Why The remote server returned an error: (400) Bad Request.?


having my first crack at implementing a Restful WCF service but cant get it to Post my object :( It crashes in the clientstuff code (see below). What could be the fix?? thanks

part web.config

<system.serviceModel>
    <services>
      <service name="MyRest.Service1" behaviorConfiguration="ServBehave">
        <!--Endpoint for REST-->
        <endpoint address="XMLService" binding="webHttpBinding" behaviorConfiguration="restPoxBehavior" contract="MyRest.IService1" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServBehave">
          <!-- 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 for the REST endpoint for Help enability-->
        <behavior name="restPoxBehavior">
          <webHttp helpEnabled="true" />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

client code:

 public string ClientStuff()
        {
            var ServiceUrl = "http://localhost/MyRest/Service1.svc/XMLService/";
            var empserializer = new DataContractSerializer(typeof(MyRest.Employee));
            var url = new Uri(ServiceUrl + "PostEmp");
            var request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "POST";
            request.ContentType = "application/XML";
            var emp = new MyRest.Employee { DeptName = "sale", EmpName = "ted", EmpNo = 11112 };
            using (var requeststream = request.GetRequestStream())
            {
                empserializer.WriteObject(requeststream, emp);
            }
            var response = (HttpWebResponse)request.GetResponse();// crashes here with error in title
            var statuscode = response.StatusCode;
            return statuscode.ToString();
        }

service1.svc.cs

 public bool PostEmp(Employee employee)
        {
            //something
            return true;
        }

servicecontract

[ServiceContract]
public interface IService1
{
    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "/PostEmp", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    bool PostEmp(Employee employee);

    // TODO: Add your service operations here
}

Solution

  • There are a couple of things you should fix. The first one is of course to use the proper content type header, there's no such thing as application/XML:

    request.ContentType = "text/xml";
    

    and the other, and more important thing is to ensure that you are referencing the exactly same Employee class in your server and client, otherwise the client data contract serializer will emit a different namespace in the XML making the server crash. Basically this Employee class should be declared in a shared class library between your server and client application.

    And by the way to more easily be able to debug this kind of problems by yourself in the future instead of posting questions here simply enable tracing on your service side:

    <system.diagnostics>
        <sources>
            <source name="System.ServiceModel" 
                    switchValue="Information, ActivityTracing"
                    propagateActivity="true">
                <listeners>
                    <add name="traceListener" 
                         type="System.Diagnostics.XmlWriterTraceListener" 
                         initializeData= "c:\log\Traces.svclog" />
                </listeners>
            </source>
        </sources>
    </system.diagnostics>
    

    and then use the built into the .NET SDK trace viewer (SvcTraceViewer.exe) to simply load the generated log file and everything will be shown and explained to you in with a GUI (that looks like coming from the 90s but does the job).

    Ah and by the way you might need to disable ASP.NET compatibility by removing the following line from your web.config:

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    

    I am not 100% sure but IIRC this was necessary with REST enabled services (might be wrong though on this one).