Migrating ASMX Service to WCF Service - AJAX Post - c#

I have a asp.net asmx service and i would like to convert it to a wcf service.
I'm having problems calling the wcf service from jquery ajax POST request with parameters.
if i call the WCF service without parameters or pass the parameter in a json format it works OK.
When executing the below jquery post to the wcf service i get error 500.
Please note , i cannot change the way the jquery request is made.
Original ASMX Service:
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void SendStatus(string param1, string param2)
{
..................
}
jQuery POST:
var d = { param1: 1, param2: 2 };
$.ajax({
type: "POST",
url: "/Service1.asmx/SendStatus",
data: d,
success: function () { }
});
NEW WCF Service:
[OperationContract]
[WebInvoke]
public void SendStatus(string param1, string param2)
{
}
jQuery POST:
var d = { param1: 1, param2: 2 };
$.ajax({
type: "POST",
url: "/Service2.svc/SendStatus",
data: d,
success: function () { }
});

-- EDIT --
I recall this issue drove me nuts once before, so I went back for another look. Sure enough ... Given the requirement that the Javscript remain as written, I maintain that this is literally impossible with the current release of WCF. Consider the following points:
1) You need to use webHttpBinding, because that's the only binding that supports REST style services (basicHttpBinding and WSHttpBinding both use SOAP wrappers). (ref. here: BasicHttpBinding vs WsHttpBinding vs WebHttpBinding)
2) The AJAX call as written in this question uses a content-type of "application/x-www-form-urlencoded" (you can confirm this using Fiddler).
3) You can also confirm that WCF throws an exception before the service method even gets invoked. The exception is as follows:
The body style 'Bare' is not supported by 'WebScriptEnablingBehavior'. Change the body style to be 'WrappedRequest'.
But "bare" body style is Microsoft-speak for a REST request using basic parameters (ie, not "wrapped" in JSON or XML). That is, there is no possible configuration that would allow WCF to handle this specific AJAX request. You can even implement your own WebContentTypeMapper, and it still won't work. This guy is on to them: http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2473190-consider-making-the-system-servicemodel-channels-r
My conclusion is that (given you can't use MVC, which would make this a piece of cake), you need to somehow route this request to a basic .ASPX page, and use the trusty old Webforms methods (Page.IsPostBack, Request.Params["param1"], etc).
-- END EDIT --
Per the other thread above, looks like there are a few parameters you need to add/fix in your AJAX call:
...
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(d)
...

If you can't change the client-side code, you should not migrate these endpoints from ASMX to WCF. WCF uses a different, less-flexible serializer than ASMX and it's likely that you'll run into trouble that can only be resolved by changing how data is sent, received, and/or handled on the client-side.
If you're willing to deal with that turmoil anyway, a much better migration path would be waiting until ASP.NET Web API is shipped and moving to it. If you move to WCF now, you'll just be behind again later this year when Web API is released.

I think you have to pass string parameter values in double quotes (""). Like this:
var d = { param1: "1", param2: "2" };
$.ajax({
type: "POST",
url: "/Service2.svc/SendStatus",
data: d,
success: function () { }
});
Hope this will work.
500 error code means parameter values didn't match with required values.

Related

URL to call the JSON WebService produced into ASP.NET

I have done a web service using Visual Studio 2012 into C#.
I'm usually use SOAP but now I need to use JSON.
So I've used this code to create a SOAP method:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string test()
{
var testArray = new List<clienti>();
testArray.Add(new clienti() {nome = "Mark", cognome = "Reed", email = "mark.reed#test.com"});
var serializer = new JavaScriptSerializer();
return serializer.Serialize(testArray);
}
Can I call this method directly from an URL?
(that is the real goal that I want to obtain)
A stuff like this: http://ws.mysite.com/serice1.asmx/test.
If I try to type the URL with the name of the method after the slash not return data but an error on the URL format!!!
In debug mode all works perfectly if I click the button method
So the answer to your question is Yes I believe, but let's start for sure with an Ajax scenario that 100% works.
Something I want to clarify for you though, your "test()" method in service1.asmx is not a "Soap method" as you called it. Its a "Web Service method" and it returns JSON. It is callable using HTTP protocol or SOAP protocol. Because you added the [ScriptMethod] to the Web Method you can now call it using an HTTP Get request. If you remove the [ScriptMethod] attribute, you can only call "test()" with an HTTP POST request or a SOAP request.
The following jQuery Ajax call will work with service1.asmx/test:
$.ajax({
type: "POST",
url: "Service1.asmx/test",
data: "{ ifTestHadAParameter: 'hello world'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
var myData = JSON.parse(data.d); // data.d is a JSON formatted string, to turn it into a JSON object
// we use JSON.parse
// now that myData is a JSON object we can access its properties like normal
}
});
If you are using ASP.NET 3.5 or below, ASP.NET Web Services wrap JSON responses to HTTP Get and Post requests in an outer JSON {} to project against a certain type of hacking. Hence the data.d in my jQuery Ajax code snippet. If you using ASP.NET > 4.0 then, in your success function data contains your response from service1.asmx/test, no data.d required.
Now to call http://ws.mysite.com/serice1.asmx/test, this will not work in a "browser" as you say but you probably ultimately do not want to use the URL in a browser, that is just how you stated your question for simplicity.
You need to format your Get request correctly with http://ws.mysite.com/serice1.asmx/test.. So in C#, using the HTTPRequest .NET lib you should be able to prepare a proper HTTP Get Request to call your Web Services URL, basically simulating a browser request in your C# code if you have the right contentType in your Get request header.
A great tool to use for this problem is called Fiddler, you can easily create HTTP Get requests and change the content type.
No as asmx webservices have no router's like webapi or MVC best create a webapi project, add a controller with empty read write methods and return your array in there it will serialize automatically in JSON,XML or BSON default JSON (you can change this in the accept header in you client request) example method
public class mycontroller: ApiController
{
public string Get()
{
var testArray = new List<clienti>();
testArray.Add(new clienti() {nome = "Mark", cognome = "Reed", email = "mark.reed#test.com"});
return testArray ;
}
you can access the url like this site/api/controller

$.ajax POST call to ServiceStack webservice, parameter not arriving

I am trying to learn how to program a web service with ServiceStack and call it via ajax in JavaScript. I did this by watching the pluralsight movies and I think I almost figured it out how to do that except for passing data as parameters with a service call.
I try to call the service with this ajax-call:
var request = { };
request.Amount = 32;
$.ajax({ type: 'POST',
contentType: 'application/jsonp; charset=utf-8',
url: "http://localhost:1879/entry",
dataType: 'jsonp',
data: {request: request},
success: function(result){
alert(result.Id);
}});
The service looks like this:
public class EntryService : Service
{
public object Post(Entry request)
{
return new EntryResponse() { Id = request.Amount };
}
}
[Route("/entry", "POST")]
public class Entry
{
public int Amount { get; set; }
}
public class EntryResponse
{
public int Id { get; set; }
}
I expect the alert in the callback to show the number 32, but it shows the number 0. And when I debug my service I see that request.Amount is 0 as well, so I think I do something wrong at the Ajax service call but I cannot figure out what. So I wonder what I am doing wrong here.
author of that Pluralsight course here. Hopefully I can help you.
First thing you should do is make sure the API is working correctly.
Go to this: http://localhost:1879/entry
In your web browser you should see a page displayed that has information about the service. If you don't your URL is wrong or ServiceStack is configured wrong.
Assuming the URL is correct, all you should need to do is wrap your data in JSON.Stringify().
When you do a post, the data has to be in JSON format as a JSON string. You are currently sending a JSON object.
Also, most likely you can drop the localhost bit off your url in the $.ajax call and just do "entry"
You can not do a post with JsonP. If you are trying to do a cross domain POST you need to look into cors and make sure that is enabled for the the service you are POSTing to.
Post data to JsonP
I only used jsonp cause I read and hoped that it could be the solution for my problem. But based on your explanation I shouldn't need it, so I changed my code to this:
var request = { };
request.Amount = 32;
$.ajax({ type: 'POST',
contentType: 'application/json; charset=utf-8',
url: "http://localhost:1879/json/reply/Entry",
dataType: 'json',
data: request,
success: function(result){
alert(result.Id);
},
error: function(xhr, ajaxOptions, thrownError){
alert("Failure!");
alert(xhr.status);
alert(thrownError);
}});
First I had this call without the error part and nothing happened, no alert, no error, nothing. So I assumed the error was consumed instead of being showed, so I added the error callback and my assumption seemed to be right. Now I get 3 alerts and the last 2 alerts shows "400" and "bad request".
I searched on those errors and tried but none of the possible solutions I found fixed my problem. I tried 2 urls: /json/reply/Entry and /entry after the localhost part but both didn't work. So what am I doing wrong?

JSONP no get value result

I'm doing a project for college where one WebSite sends commands to a Windows Forms application. This application is responsible for access to serial port and send and receive commands.
Communication between the Website and the Windows Forms application, I used Web Api, however after publishing, auditioning remembered that the localhost in a C # WebSite. Net's own site and not my Windows Forms application.
I changed the call to the Web Api directly use Ajax and not a controller.
In the examples I found I saw that I use JSONP, but I can not read the results and use it on my website.
The calling code and return seen by Chrome are below
function cmdLocal() {
$.ajax({
type: "GET",
dataType: "jsonp",
url: "http://local host:8089/api/gps/",
jsonpCallback: "cmdTorre",
jsonp: "cmdTorre"
});
}
function cmdTorre(data) {
alert(data);
}
Response Header
Content-Length:10
Content-Type:application/json; charset=utf-8
Date:Tue, 10 Jun 2014 11:18:30 GMT
Server:Microsoft-HTTPAPI/2.0
Response
No Properties
Windows Forms APIController
namespace TCCWindows.Lib
{
public class GPSController : ApiController
{
[HttpGet]
public string Posicao()
{
var coordenada = TCCWindows.FormPrincipal.PegarCoordenadas();
return coordenada.Latitude + "|" + coordenada.Longitude + "|" + coordenada.Altitude;
}
}
}
First, you ajax call looks overly complicated try replacing it with :
function cmdLocal() {
$.ajax({
type: "GET",
dataType: "jsonp",
url: "http://local host:8089/api/gps/",
success: cmdTorre,
error: function(err){
alert("You have a error"+err);
}
});
}
function cmdTorre(data) {
alert(data);
}
Please validate the new code carefully. I just typed it in here so can have errors. If this runs at this point you should probably see the error message. That is because your GPSController doesnt seem to be returning a valid JSONP (or JSON for that matter). Please read up on JSONP for more clarification but, I think if you modify your return statement to make it look like following, it should work. Assuming your controller is actually getting called and your network stuff is working:
return "cmdTorre({\"lat\":"+coordenada.Latitude+" , \"lon\":"+coordenada.Longitude+" });"
Basically your return string should look like following when printed on console:
function cmdTorre({
"lat": 23.34,
"lon":34.23,
"alt":50
});
Again I suggest you check the code I wrote for syntax issues as i just typed it up in here, but it should give you the idea.
So problems were:
The return string you are generating is NOT in JSON format
It is also not wrapped in a function call making it a invalid JSONP too.
Lastly my solution should get your code working and JSONP started but its not the right way to do things. Its more of a ugly hack. Your GPS controller should read the HTTP request for parameter called 'callback' which is a accepted convention for JSONP calls. Then instead of hardcoding the function name in the return statement, you should use the value of this callback parameter. Then you dont need to use a specific function like 'cmdTorre' in your jQuery. Instead a anonymus function like success:function(response){...} will work just fine.
Hope that helps.

Cross Domain jQuery Ajax Using C# and WFC

I have a small webservice written in C# and WCF.
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello Worlds";
}
}
I have a little jQuery code;
$.support.cors = true;
$.ajax({
type: "POST",
url: "http://localhost:61614/Service1.asmx/HelloWorld",
data: '{}',
dataType: "json",
success: function (msg) {
alert(0);
}, error: function (a, b, c) { alert("Err:" + c );
}
});
This calls the webservice. There are no problems making the call, but it errors out on the return.
The webservice is in one application, and the Web page is simply an HTML page on it's own. Eventually, the HTML will be used within PhoneGap.
I have tried all sorts of things.
Adding in contentType: "application/json; charset=utf-8", causes the whole call to fail.
Using dataType: 'jsonp" causes call to fail.
Basically, the above calls the WS but errors out on return which is weird.
My requirement is that I need to return a JSON object from the webservice, and it has to work in Safari.
Does anyone have complete sample code of a JSONP call?
From jQuery getJSON:
If the URL includes the string "callback=?" (or similar, as defined by the server-side API), the request is treated as JSONP instead. See the discussion of the jsonp data type in $.ajax() for more details.
In order for your request to be treated as a JSONP request, you need to include callback=? in your URL. This tells jQuery to create a callback function and pass the name of that function as the callback parameter to your server.
In the server-side code, your method must then return JSON code wrapped, or padded, with the name of the JavaScript function passed in as the callback parameter in the query string.
Essentially, what you're doing is returning JavaScript to the client browser, which runs immediately, and invokes a function already defined in the context of the page.
JavaScript:
$.getJSON("http://localhost:61614/Service1.asmx/HelloWorld?callback=?",
function(data) {
// alert raw JSON data
alert(JSON.stringify(data));
// access the "say" property and alert it
alert(data.say);
}
);
Server-Side:
This is a crude version of what you'd need to do on the server-side:
// get the callback parameter value and assign to the String callback
...
return callback + "( { 'say' : 'HelloWorld' } );";
Further technical explanation of what is happening under the hood:
While this is not something you need to know today, this may help you understand more about how jQuery is implementing JSONP.
This evaluates to something that might look like this:
return "jquery43214321432143242({'say':'HelloWorld'});"
where jquery43214321432143242 is the random name given for your success callback function. Again, since the returned text is returned using text/javascript, it runs immediately, passing the {'say':'HelloWorld'} object in as a parameter to the function.
The resulting output should be an alert message representing the raw JSON, and the words "HelloWorld", pulled from the .say property.

Making a $.post call with jquery 1.7.1 to a WCF rest service

So I have the following working:
$.ajax({
type: 'POST',
url: 'user',
data: '{"FirstName":"John","LastName":"Doe"}',
contentType: "application/json",
dataType: 'json',
success: function (data) {
alert('success!' + data.Id);
}
});
however this fails (which should be equivalent):
$.post('user', '{"FirstName":"John","LastName":"Doe"}');
Any idea what's wrong? Is $.post somehow incompatible with WCF rest?
No, the two are not equivalent at all. Look with FireBug, Fiddler, ... and compare the 2 requests. In the second example you are not setting the contentType: "application/json" request header. You are not setting it because the $.post method doesn't allow you to.
And the server doesn't accept your request because since you are trying to POST to a JSON enabled service, it expects the request to be JSON and of course the client to set the application/json content type request header. You are posting some string and since you don't indicate what this string represents through the content type header, the server doesn't know what to do with it and drops the request.
This is to say that you should use $.ajax as in the first example to invoke your service. Actually I'd recommend you a slight modification and instead of:
data: '{"FirstName":"John","LastName":"Doe"}',
use:
data: JSON.stringify({"FirstName":"John","LastName":"Doe"}),
This will ensure that if tomorrow you decide to deal with someone else than Mr. Jon Doe, like for example Mr. Jon O"Hara, your JSON will still be properly encoded which is what the JSON.stringify method does. It is natively built into modern browsers but if you need to support some legacy browsers you could include the json2.js script to enable it.

Categories