wcf REST Services and JQuery Ajax Post: Method not allowed

h3n picture h3n · Jul 9, 2011 · Viewed 27k times · Source

Anyone knows what's wrong with this? I cant get the json response from my wcf rest service.

Jquery



$.ajax({
  type: 'POST',
  url: "http://localhost:8090/UserService/ValidateUser",
  data: {username: 'newuser', password: 'pwd'},
  contentType: "application/json; charset=utf-8",
  success: function(msg) {
   alert(msg);
  },

  error: function(xhr, ajaxOptions, thrownError) {
   alert('error');
  }

});


Service



  [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class UserService: IUserService
    {
        private readonly IUserRepository _repository;

        public UserService()
        {
            _repository = new UserRepository();
        }

        public ServiceObject ValidateUser(string username, string password)
        {
           //implementation
        }
    }

    [ServiceContract]
    public interface IUserService
    {
        [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
        [OperationContract]
        ServiceObject ValidateUser(string username, string password);
    }


web config



 <system.serviceModel>

    <!--Behaviors here.-->
    <behaviors>
      <endpointBehaviors>
        <behavior name="defaultEndpointBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>

      <serviceBehaviors>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <!--End of Behaviors-->

    <!--Services here-->   
   <services>
      <service name="MyWcf.Services.UserService">
        <endpoint address="UserService" behaviorConfiguration="defaultEndpointBehavior"
          binding="webHttpBinding" contract="MyWcf.Services.IUserService" />
      </service>
    </services>

    <!--End of Services-->

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint name=""
                          helpEnabled="true"
                          automaticFormatSelectionEnabled="true"
                          defaultOutgoingResponseFormat ="Json"
                          crossDomainScriptAccessEnabled="true"/>
      </webHttpEndpoint>
    </standardEndpoints>
  </system.serviceModel>


Answer

Ladislav Mrnka picture Ladislav Mrnka · Jul 9, 2011

I see multiple problems in your code:

405 means method not allowed - it can mean that you are posting data to wrong resource. Are you sure that your address is correct? How do you expose the service? Is it .svc file or ServiceRoute? If it is .svc file the address will be UserService.svc/UserService/ValidateUser

  • UserService.svc because this is entry point for your service (if you are using ServiceRoute you can redefine this
  • UserService because you are defining this relative address in endpoint configuration
  • ValidateUser because that is default entry point for your operation

Now your JSON request is completely bad and your method signature as well. Method signature in your service contract must expect single JSON object = it must be single data contract like:

[DataContract]
public class UserData
{
    [DataMember]
    public string UserName { get; set; }

    [DataMember]
    public string Password { get; set; }
}

and operation signature will be:

[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract]
ServiceObject ValidateUser(UserData userData);

There is no wrapper element in JSON request and because of that you must use Bare. Also it is not needed to set response format because you will set it on endpoint level (btw. you must also set request format if you don't).

Once you defined data contract for your request you must correctly define ajax request itself:

$.ajax({
  type: 'POST',
  url: "UserService.svc/UserService/ValidateUser",
  data: '{"UserName":"newuser","Password":"pwd"}',
  contentType: "application/json; charset=utf-8", 
  success: function (msg) {
    alert(msg);
  },

  error: function (xhr, ajaxOptions, thrownError) {
    alert('error');
  }

});

JSON object is as string! and all its members as well!

For last modify your configuration to:

<system.serviceModel>
  <services>
    <service name="UserService.UserService">
      <endpoint address="UserService" kind="webHttpEndpoint" contract="UserService.IUserService" />
    </service>
  </services>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
  <standardEndpoints>
    <webHttpEndpoint>
      <standardEndpoint helpEnabled="true" automaticFormatSelectionEnabled="true" />
    </webHttpEndpoint>
  </standardEndpoints>
</system.serviceModel>

If you want to use standardEndpoint you must use kind in endpoint definition and you don't need to specify behavior (it is part of standard endpoint). Also you are not using cross domain calls so you don't need to enable them and you don't need default format because it is resolved automatically.