JQuery AJAX call fails while other calls to WCF service succeed - wcf

I am trying to set up a simple WCF REST service that we will be able to call from jquery. When I visit the URL in the browser, I get a response back. When I attempt to send an HTTPRequest directly (using the Firefox plugin RESTClient), I get a response back. These responses look correct to me, containing headers and a string of JSON and apparently nothing else.
However, when I call this same service via a jquery.get() or jquery.post() call, nothing happens. Using the jquery.ajax() call reveals the error callback gets called, but to me the data given to the error callback doesn't give me clues as to why this isn't working.
<a id="thelink" href="javascript:void(0)">GO</a>
<script type="text/javascript">
function doAjax() {
$.ajax({type: "POST",
dataType: "json", // see note below
url: "http://localhost:54459/MySimpleService.svc/json/24",
success: function(jqXHR, textStatus) {
alert("success");
},
error: function(jqXHR, textStatus, errorThrown) {
alert("error");
}
});
}
$('#thelink').click(doAjax);
</script>
Note: for the dataType parameter I have tried all of "text", "json", "jsonp" and leaving the parameter off. Similarly, I have tried with both GET and POST (modifying the web service to respond to GET or POST respectively).
The method called at that endpoint doesn't do anything spectacular that should be failing -- it simply concatenates the string to a constant and returns (just testing at this point, it will clearly do more interesting things in the future)
Firefox shows me getting back 200 OK when I click the link.
The WCF service is running out of my Visual Studio 2010 debug environment. It hits breakpoints placed in the method that responds to this service method.
I have tried accessing the html posted above from a file on my local machine (port 80) as well as hosting it elsewhere, with the same results. Could this be a security issue?
The values passed to the error callback don't seem terribly helpful:
jqXHR - readyState : 0, status : 0, statusText : error
textStatus - "error"
errorThrown - ""
So, why does my service seem to work, for GET or POST, when I call the url in a browser or RESTClient, but fail when I attempt to call it from jquery.ajax()?
EDIT: after more tests based on the comments I received, I tried hosting the page with the javascript on the same port as the web service, and this shows success. In my real-world scenarios, I won't have the luxury of hosting the client side code and the web service on the same domain/port. I'm assuming this is a security model issue -- where do I look to allow this sort of access (whitelisting domains/ports or otherwise)

The issue seemed to be in my web.config; as we worked out in comments, the issue is one of cross-domain security. I was already using a webHttpBinding on my endpoint, but did not realize it needed to be configured:
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingWithJsonP" crossDomainScriptAccessEnabled="true"/>
</webHttpBinding>
</bindings>
...
</system.serviceModel>
Setting crossDomainScriptAccessEnabled="true" seems to have done the trick. Note that I already have <serviceMetadata httpGetEnabled="true"/> as part of my service behavior.

make sure you have already configured your service to be called from script clients: adding a couple of elements in web.config in your service:
<behaviors>
<endpointBehaviors>
<behavior name="webScriptEnablingBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
more info here: http://msdn.microsoft.com/en-us/library/bb763177(v=vs.90).aspx
hope it helps,

Related

Disable WebFaultClientMessageInspector in WCF Client?

I'm using WCF to invoke a remote REST API, and am getting a 500 Internal Server Error from the service. Using Fiddler, I can see the body of the 500 response (which includes, buried in HTML, the reason for the 500 error). I would like to be able to examine the response body in .Net, but it appears that the WebFaultClientMessageInspector gets there first, and throws a vague exception.
Is there anyway to disable/override this inspector (and see the full response body)?
I think I've figured this out - I do need a custom message inspector (IClientMessageInspector), but I also need to configure it FIRST in my WCF Endpoint configuration:
<endpointBehaviors>
<behavior name="myCustomErrorWebHttp">
<myCustomnClientBehavior />
<webHttp />
</behavior>
</endpointBehaviors>
Doing THIS caused my inspector to be triggered BEFORE WebFaultClientMessageInspector, and I was able to inspect the message body.
From this link
How to solve this problem? The answer is obvious: create custom
implementation IClientMessageInspector and use it on client.
Full details is in the link.

WCF service generated from WSDL not able to use same contract

I have wsdl which was generatede by JAX-WS RI of a working web service, but i don't have access to the service itself.
Now what i would like to do is, to create my own WCF service out of the wsdl that i got. So i could just switch url's in the config file.
I created service interface with svcutil.exe.
svcutil my.wsdl my.xsd
All seemed ok until i tried to check my service via browser, i got:
The operations X and Y have the same action (). Every operation must have a unique action value.
Hmm.. ok. i checked the interface and realized that, yes, code generator has given each operation same name - "".
[System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="*")]
So i replaced all these linse with plain [OperationContract] and all seemed to work well until i tried to call my service from client. In config i just modified endpoints address.
The exception i got was: The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher
To me it seems like client is requesting operation with no name. How is it possible that working service knows which operation to use?
If i add new my service as a new service reference, all works fine.
What am i missing here?
How can i make WCF service to work on same contract it was generated from?
EDIT:
I did some more debugging. I creted opration
[OperationContract(Action = "*", ReplyAction = "*")]
public object UnknownAction()
{
return null;
}
When i add breakpoint to this operation i see from OperationContext.Current.IncomingMessageHeaders.Action that Action is empty. Message body is totally correct though.
Is there some kind of behavior i need to define on the server side?
current behavior configuration looks like this:
<behavior name="svcBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
EDIT vol2
When i create asmx web service and try to call web method from client, i get SoapException: Server did not recognize the value of HTTP Header SOAPAction: .

WCF 4.0 Cookie Only First is Recorded by Browser

I am working on the fastest way to write cookies from a WCF self hosted console app REST service with WebHttpBinding.
I prepare the "Set Cookies" but only the first cookie is set in the browser (using FireFox 11.0 on Windows) as well as the "Expires" value.
var expiry = DateTime.Now.AddMonths( 6 );
var outresp = WebOperationContext.Current.OutgoingResponse;
outresp.Headers.Add( HttpResponseHeader.SetCookie , "cookie1=fd9416ea-2705-4d44-be76-f2f7b95e6b13; cookie2=7d489e69-d9c9-4b8d-a4b1-bce0da1c5966;expires=" + expiry );
I also tried putting a comma between the first cookie and the second one, that did not work either:
outresp.Headers.Add( HttpResponseHeader.SetCookie , "cookie1=fd9416ea-2705-4d44-be76-f2f7b95e6b13;, cookie2=7d489e69-d9c9-4b8d-a4b1-bce0da1c5966;expires=" + expiry );
I cut this down, and fired up Fiddler:
outresp.Headers.Add( HttpResponseHeader.SetCookie , "foo=foovalue;,bar=barvalue;" );
and Fiddler shows this:
Response sent 27 bytes of Cookie data:
Set-Cookie: foo=foovalue;,bar=barvalue;
This response did not contain a P3P Header.
Validate P3P Policies at: http://www.w3.org/P3P/validator.html
Learn more at: http://www.fiddler2.com/redir/?id=p3pinfo
Which tells me that I am not formatting things on the .NET side to make the cookies acceptable to the browser.
How can I get all of the cookies into the browser insetad of just the first value? What did I miss?
Thanks.
[ EDIT ]
I took the issue to Microsoft for support, and learned this:
The fact that "Set-Cookie" is munged into a single cookie line is logged as a bug within Microsoft for .NET Framework 4.0 and also Framework 4.5.
Within the Microsoft WCF development group, the bug is listed as "closed" and "won't fix".
According to Microsoft, the only workaround is to move from self-hosted to hosting within IIS and then using the (IIS) Response object directly (different code path that does not have the bug).
Although this is an older post, since this is still an ongoing issue and using the AspNetCompatibilityMode with WCF has significant performance downside, the option that MSFT has supplied is not viable under many/most/any circumstances. I'm going to answer this question late since this issue is still lingering.
The only way to resolve this issue is to output the Set-Cookie response header just as you've shown, but to process that response header on the client side with javascript and place it in to the browser since, as you've noted, the browser will not handle this response. Neither will applying more than one Set-Cookie response header work as noted in this bug I created.
http://connect.microsoft.com/VisualStudio/feedback/details/779111/wcf-rest-service-two-set-cookie-http-headers-invalid-set-cookie-header-syntax
So, process the response header and use document.cookie in client-side javascript to place the cookies in the browser within the success handler of your jQuery .ajax request.
To expand on #jeff-fischer 's answer, AspNetCompatibilityMode does work and requires the following:
AspNetCompatibilityRequirements is set for the service class to either Allowed or Required e.g.:
[AspNetCompatibilityRequirements(RequirementsMode
= AspNetCompatibilityRequirementsMode.Allowed)]
public class AppService : IAppService
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> is set in <system.serviceModel>
This then gives access to HttpContext (you'll need using System.Web; to get access to this) and cookies can be set using:
var aCookie = new HttpCookie("foo")
{
HttpOnly = true,
Value = "bar",
Expires = DateTime.Now.AddDays(1)
};
HttpContext.Current.Response.Cookies.Add(aCookie);
This will then need to be run as an application on IIS rather than though the WCF launcher and if multiple cookies are set, multiple cookie headers will actually appear.

Calling WCF/JSON/REST WebService from JavaScript using jQuery/Ajax

I know there are a lot of questions out there about this - believe me I've read a lot of them and tried the answers out.
(This project is for an internal company lan, not the internet)
We have a WCF webservice which is RESTFUL and sends/receives JSON, it requires NTLM (Kerb would also be good) auth/credentials to ensure that the calling user (from the browser is who they say they are), and this is negotiated between the browser/client and the service by the WCF bindings:
<bindings>
<webHttpBinding>
<binding name="webHttpBindingAuth">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm"/>
</security>
</binding>
</webHttpBinding>
</bindings>
Using Fiddler, I can call the methods on the service GET and POST successfully and provided I adjust the JSON we're sending to the webservice (to include the session ID for example) it trundles along happily.
The problems started when we tried to use JavaScript/jQuery to call the webservice; the idea is that a web server will supply the HTML/JS to the client browser, the browser should then call the WCF webservice to get a session and allow a user to perform a few actions (we have 3 methods in total).
Firstly, we ran into the X-Domain issue, which we tried to resolve by getting the web server to return the correct headers (Access-Control-Allow-Origin). This didn't prevent browsers like SRIron from telling us that;
XMLHttpRequest cannot load http://{webServiceUri}/InstantMessagingService/chat/start/{username}. Origin http://{web**Server**Uri} is not allowed by Access-Control-Allow-Origin.
Following this, I investigated the possibility of using Silverlight (doesn't seem to support NTLM auth over WebHttpBinding), reverse proxy is out, as the IIS server being used in dev won't be used in prod (I believe it is WebSphere, but not under our control); next I looked at this:
http://msmvps.com/blogs/paulomorgado/archive/2007/04/27/wcf-building-an-http-user-agent-message-inspector.aspx
Which left me under the impression that the WCF web service was in fact the thing that needed to tell the browser where it was allowed be called from (if that makes sense). Having implemented all the code from the example, I found that the ApplyClientBehavior was never called to attempt to return the headers to the client (monitoring this in Fiddler too). Some more Googling led me to:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/707aa031-f4ff-47ab-ba5b-730f7930605e/
Since we're accessing the web service using jQuery and not some .NET client/service reference/proxy/app.. blah, I'm thinking that it's not possible to pre-request-send these headers to allow access to the service. Also, Fiddler seems to think that it's getting a 401 Unauthorized when it does make the attempt to call the http://../chat/start/.. method.
Here's the jQuery I'm using to attempt to make the call (I supplied a few settings in the hope it was going to work):
var url = webserviceUrl + "chat/start/" + remoteUserUri;
$.ajax({
type: 'GET',
url: url,
crossDomain: true,
beforeSend: function(xhr){ xhr.withCredentials = true; },
contentType: "application/json; charset=utf-8",
success: function (data) { conversationStarted(data); },
dataType: 'json'
});
Ok, if anyone has helpful hints or ideas, please fire away. I'll reply and edit etc. to make sure this is kept up to date, I hope I haven't missed anything (but my heads spinning a little from my Googling).
Also, I know that there might be better ways to do this, but I'd like to do it in the cleanest/quickest way from where I am now - i.e. not a lot of code changes, rewrites etc. I can also post up configs if people think they really are useful.
In the end I had to kind of work around, we got the guys in charge of the web server to agree to serving up an IFrame which points to our IIS hosted page (the one containing the JS etc.)
Then using the magic of WCF/Windows we host the WCF services on port 80 which gets around the X-Domain origin stuff. So I can then have REST/JSON without having to use JSONP.
I know it's not the answer to the question given the criteria I specified, but I think I ran out of options completely in the end.
Can you use JSONP? It'll solve your cross-domain problem in a heartbeat.

404 not found when accessing JSON WCF Service with jQuery

I have a WCF service hosted in IIS which seems to be running fine but am unable to access it through jQuery on the client side.
My site structure is like this -
localhost:9080/Website
localhost:9080/WCFService
I've set the anonymous authentication user id to that of the AppPool identity.
When I try to access a GET method from the browser, it returns the JSON data just fine. But when I try to access the same method from the client using jQuery $.ajax() the server returns a 404 error.
The URL of the WCF method is
localhost:9080/WCFService/Service.svc/SimpleMethod
The signature of the method is
string SimpleMethod()
I've already tried looking articles online and I don't think the web.config is any different. It looks like a permissions thing to me.
Can anyone shed any light on this issue?
-Thanks!
Here's what I did -
Added an endpoint behavior which uses <webHttp /> and removed <enableWebScript />. That fixed it.
When I try to access a GET method from
the browser, it returns the JSON data
just fine
You are accessing from the server pc and using http://localhost:9080
But when I try to access the same
method from the client using jQuery
$.ajax() the server returns a 404
error.
What URL are you using for ajax call? Use relative URL.
It looks like a permissions thing to
me.
If on same machine (server machine) invoking directly from browser works but invoking using ajax from same client does not work, it can be a wrong url
You better post your ajax calling code.