4

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>


h3n
  • 5,142
  • 9
  • 46
  • 76

3 Answers3

9

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.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • I followed your modification and when I tried it, it says: Operation 'ValidateUser' of contract 'IUserService' specifies multiple request body parameters to be serialized without any wrapper elements. At most one body parameter can be serialized without wrapper elements. Either remove the extra body parameters or set the BodyStyle property on the WebGetAttribute/WebInvokeAttribute to Wrapped. – h3n Jul 11 '11 at 11:15
  • So you didn't follow my modifications because my `ValidateUser` doesn't have multiple request body parameters. – Ladislav Mrnka Jul 11 '11 at 11:18
  • I've changed the parameter to UserData and when I ran it, "Method not Allowed". In Global.asax, I put the ff and it works: HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*"); HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods","GET, POST"); HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers","Content-Type, Accept"); HttpContext.Current.Response.End(); – h3n Jul 13 '11 at 08:44
  • Is there a way to Post Data into the Service without doing anything on the Global.asax? – h3n Jul 21 '11 at 09:41
  • 1
    Yes there is a way because I have tested exactly changes I described with .aspx page using jquery and both the page and service hosted on my local IIS and it worked without any problem and without any needs to modify headers. – Ladislav Mrnka Jul 21 '11 at 10:45
2

I believe Ivan is on the right track here!

You are calling your service from javascript in a browser, right?

Does the html page with that javascript reside in the same domain as the wcf service?

If they are not in the same domain, then I would say that it is a cross-site-scripting issue. I believe GET is allowed cross-sites, but POST are not. http://en.wikipedia.org/wiki/JSONP would be a solution, if it's supported server-side (by WCF)

Joakim
  • 103
  • 5
  • You have mentioned POST is not allowed in cross domain WCF REST JQuery Ajax Call. Can you give me the source for it? Because, from your post only I learnt POST is not supported for cross-domain. I wanted to use POST due to security, but it doesn't work. – Firnas May 21 '13 at 07:23
  • It's explained quite ok at http://en.wikipedia.org/wiki/Same_origin_policy but if you're looking for answers, you can find a number of suggestions here on SO e.g. http://stackoverflow.com/questions/298745/how-do-i-send-a-cross-domain-post-request-via-javascript – Joakim Jun 21 '13 at 20:48
1

You tested on one domain I suppose the author try to make call from different domain. It could be impossible due to cross domain calls.

Ivan
  • 11
  • 1