WCF + Json = wrong serialization - asp.net

Why this WCF 3.5 method
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Json
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public string Upper(string text)
{
return text.ToUpper();
}
}
returns {"d":"TEXT"} ?
It should returns {"TEXT"}
I'm calling using jQuery.
$("#upper").click(function() {
$.ajax({
type: "GET",
url: "/Json.svc/Upper?text="+$("#input1").val(),
success: function(data) {
$("#input1").val(data.d);
}
});
});

This is a security feature that has been added to the JSON serialization in .NET 3.5. It's a container object, so instead of, say, results[0], you would just say results.d[0]. Read this article for more information.

I'm assuming you are using <enableWebScript/> in your behavior config, replace that with <webHttp defaultOutgoingResponseFormat="Json"/> and you will get json without the root "d" and without the "__type" props.
However, I've only tested this in 4.0
I also don't use any attributes in code.

Have you tried changing the BodyStyle property of your [WebGet] Attribute so that responses aren't wrapped?

Related

What kind of datatypes should I use for the return value of a Web API method?

I have a Web API controller that returns data to my client. The code looks like this:
[HttpGet]
[ActionName("Retrieve")]
public IEnumerable<Reference> Retrieve(int subjectId)
{
return _referenceService.Retrieve(subjectId);
}
Can someone tell me is it necessary to specify the ActionName?
Also should I return an IEnumerable, an IList or something else?
I believe if your ASP.NET routing is setup correctly you don't need to specify the ActionName, for example:
protected void Application_Start()
{
RouteTable.Routes.MapHttpRoute("0", "{controller}/{action}/{arg1}");
}
Will match /YourControllerName/Retrieve/132
What you return is based entirely on your media-type formatters, of which the default is XmlFormatter and JsonFormatter. These can be found in GlobalConfiguration.Configuration.Formatters and will be chosen based on the Accept header provided by the client.
We, for example, use JSON.Net for our response formatting, configured by:
protected void Application_Start()
{
RouteTable.Routes.MapHttpRoute("0", "{controller}/{action}/{arg1}");
MediaTypeFormatterCollection formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.XmlFormatter);
var jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
jsonFormatter.Formatting = Formatting.Indented;
jsonFormatter.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
This tells WebApi to disallow any XML formatting and only return JSON using the provided JSON.Net contract resolver. JSON.Net supports serializing IEnumerable.
I would, however, recommend returning a HttpResponseMessage instead. This allows you to set the status code as well (This still uses the media type formatter, it's just a cleaner wrapper). You can use this like so:
[HttpGet]
public HttpResponseMessage Retrieve(int subjectId)
{
var response _referenceService.Retrieve(subjectId);
return Request.CreateResponse(HttpStatusCode.OK, response);
}
You should return HttpStatusCode instead of data if have not requirement, like POST method should return OK or whatever.
or if want record like Get method should return type of record.
also you no need to add attribute on method like Get,Put,Delete etc because webapi automatically detect method according to action like if you are getting data then your method name should be start with Get like GetEmployee etc.

Why are an MVC4 ApiControllers' methods called only based on the type and number of parameters?

I'm new to MVC, and I guess my confusion goes a bit beyond the title of this question, but for starters:
public class TestController : ApiController
{
[HttpPost]
public bool ReceiveHunk(Alterity.Models.Async.HunkDTO hunk)
{
return true;
}
[HttpPost]
public bool A(int x) { return false; }
[HttpPost]
public bool B(int x) { return true; }
}
I can't call my choice of A or B because it seems that the URL only routes to (is that the right term?) the controller, and the method is chosen based on the parameters. Since I have an (int x) on two methods, it doesn't know which to call. My confusion is exacerbated by the fact that when I do:
$.ajax({
cache: false,
type: "POST",
url: ApiLocation + 'Test',
contentType: 'application/json',
dataType: "json",
data: JSON.stringify(5),
success: function (response) { }
});
It still goes to the ReceiveHunk method, with the hunk being null. If I comment out B, ReceiveHunk is still called. Is this related to the fact that I'm using JSON instead of form url encoding? Do I have to have a separate ApiController for every method that has the same signature? Is there some way to configure the routing (or whatsit) to have the URL include the method name? A regular Controller includes the method name in the URL, why doesn't an ApiController? Furthermore, if I change either A or B take zero parameters, I simply get an internal server error (500) without any method being called and no exception. Any info that helps clear this up would be appreciated.
This is just the default routing convention for ASP.NET Web API, please read following question/answer for more details on how you can configure ASP.NET Web API routing (and have action names in routes):
Api controller declaring more than one Get statement

ASP.NET MVC 2.0 JsonRequestBehavior Global Setting

ASP.NET MVC 2.0 will now, by default, throw an exception when an action attempts to return JSON in response to a GET request. I know this can be overridden on a method by method basis by using JsonRequestBehavior.AllowGet, but is it possible to set on a controller or higher basis (possibly the web.config)?
Update: Per Levi's comment, this is what I ended up using-
protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding)
{
return Json(data, contentType, JsonRequestBehavior.AllowGet);
}
This, like other MVC-specific settings, is not settable via Web.config. But you have two options:
Override the Controller.Json(object, string, Encoding) overload to call Json(object, string, Encoding, JsonRequestBehavior), passing JsonRequestBehavior.AllowGet as the last argument. If you want this to apply to all controllers, then do this inside an abstract base controller class, then have all your controllers subclass that abstract class.
Make an extension method MyJson(this Controller, ...) which creates a JsonResult and sets the appropriate properties, then call it from your controller via this.MyJson(...).
There's another option. Use Action Filters.
Create a new ActionFilterAttribute, apply it to your controller or a specific action (depending on your needs). This should suffice:
public class JsonRequestBehaviorAttribute : ActionFilterAttribute
{
private JsonRequestBehavior Behavior { get; set; }
public JsonRequestBehaviorAttribute()
{
Behavior = JsonRequestBehavior.AllowGet;
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var result = filterContext.Result as JsonResult;
if (result != null)
{
result.JsonRequestBehavior = Behavior;
}
}
}
Then apply it like this:
[JsonRequestBehavior]
public class Upload2Controller : Controller
MVC 2 block Json for GET requests for security reasons. If you want to override that behavior, check out the overload for Json that accepts a JsonRequestBehavior parameter.
public ActionResult Index()
{
return Json(data, JsonRequestBehavior.AllowGet)
}
I also got this error when I first use MVC 2.0 using my old code in MVC 1.0. I use fiddler to identify the cause of the error. See the steps on how to troubleshoot it using Fidder -
http://www.rodcerrada.com/post/2011/07/11/jQuery-getJSON()-does-not-tirgger-the-callback-in-ASPNET-MVC-2.aspx
Is this is the security issue MVC2 was trying to address?
http://haacked.com/archive/2009/06/25/json-hijacking.aspx
If so, it seems like the vulnerability is only an issue if you are trying to do a json call to an outside website. If your MVC2 app is only making json calls to your own website (to fill jqgrids for example), shouldn't you be able to safely override the Json call in your base controller to always allow get?
Just change JSON code from :
$.getJson("methodname/" + ID, null, function (data, textStatus)
to:
$.post("methodname/" + ID, null, function (data, textStatus)

How to force ASMX web service to send JSON data to client on HTTP GET request?

I'm trying to use the official jQuery autocomplete plugin with an ASMX web service in an ASP.NET 3.5 Web Forms application. If I understand it correctly, the autocomplete plugin can only use HTTP GET to call a service (with two query string parameters: q and limit). I figured out how to make the web service respond to the HTTP GET calls, but I cannot figure out how to make it return JSON data (even though the service returns JSON data when I call it using jQuery $.ajax with type='POST', when called from the autocomplete plugin it always returns XML). Here are some code snippets:
Web service:
[ScriptService]
[WebService(Namespace = "http://tempuri.org/")]
public class UserWS: WebService
{
[WebMethod]
[ScriptMethod(UseHttpGet=true, ResponseFormat=ResponseFormat.Json)]
public List<UserDisplayInfo> GetUsers
(
string q,
int limit
)
{
List<UserDisplayInfo>users = GetUsers(q, limit);
return users.ToList();
}
}
Web page:
$("#test").autocomplete(
"./Services/UserWS.asmx/GetUsers",
{
dataType: 'json',
type: 'POST', // this setting is ignored
contentType: 'application/json;charset=utf-8',
parse: function(data)
{
//...
}
});
If this is not possible I wonder what would be a better alternative:
fixing autocomplete plugin to use HTTP POST and JSON data instead of GET and query string parameters;
using a different autocomplete plugin (I looked at a few, but at this point the official plugin has most recommendations, and I'm not sure if other plugins support HTTP POST);
an alternative to ASMX web service, such as WCF web service (I would not want to use WCF because ASMX web service is simpler to implement -- no web.config changes, no contracts, no interfaces -- and it gives me everything I need);
something else.
I found several similar questions at StackOverflow, but I did not find the answer that would work for me. Any (good) ideas?
Autocomplete plugin wants results in plain text format, not JSON. Each item should be on a separate line:
foo\n
bar\n
baz\n
Try replacing web service with generic handler (.ashx):
public class MyHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("foo\nbar\nbaz");
}
public bool IsReusable
{
get { return false; }
}
}
On the side note you can't use GET if you want ASMX web service to return JSON. See How to let an ASMX file output JSON.

ASP.NET jQuery error: Unknown Web Method

This is my first time attempting to call an ASP.NET page method from jQuery. I am getting a status 500 error with the responseText message that the web method cannot be found. Here is my jQuery $.ajax call:
function callCancelPlan(activePlanId, ntLogin) {
var paramList = '{"activePlanId":"' + activePlanId + '","ntLogin":"' + ntLogin + '"}';
$.ajax({
type: "POST",
url: "ArpWorkItem.aspx/CancelPlan",
data: paramList,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function() {
alert("success");
},
error: function(xml,textStatus,errorThrown) {
alert(xml.status + "||" + xml.responseText);
}
});
}
And here is the page method I am trying to call:
[WebMethod()]
private static void CancelPlan(int activePlanId, string ntLogin)
{
StrategyRetrievalPresenter presenter = new StrategyRetrievalPresenter();
presenter.CancelExistingPlan(offer, ntLogin);
}
I have tried this by decorating the Web Method with and without the parens'()'. Anyone have an idea?
Your web method needs to be public and static.
Clean the solution and rebuild. I've seen webmethods throw 500's until you do this.
Add public static before your method...
ex.
[WebMethod]
public static string MethodName() {}
For ajax success:
For me, it was helpful to make:
App_Start\RouteConfig
set
from
settings.AutoRedirectMode = RedirectMode.Permanent;
to
settings.AutoRedirectMode = RedirectMode.Off;
make your using method:
public
static
add:
using System.Web.Services;
and on top of method using just:
[WebMethod]
is enough
First Of All Don't Forget To Include
using System.Web.Services;
And Make Sure Your Method Should Be Public And Static and avoid adding Multiple Scripts in same Page like jquerymin.js shouldn't be used for every Function/Method in same Page
[WebMethod]
public static sting MethodName(){}
I Had The Same Issue Which Using Ajax And Jquery To Check Username Exists
Or Not.

Resources