How to output Json string as JsonResult in MVC4? - c#

This seems so simple I must be over-thinking it.
TL;DR;
How can I modify the code below to return the json object contained in the string rather than a string that happens to contain json?
public ActionResult Test()
{
var json_string = "{ success: \"true\" }";
return Json(json_string, JsonRequestBehavior.AllowGet);
}
This code returns a string literal containing the json:
"{ success: "true" }"
However, I'd like it to return the json contained in the string:
{ success: "true" }
Slightly longer version
I'm trying to quickly prototype some external api calls and just want to pass those results through my "api" as a fake response for now. The json object is non-trivial - something on the order of 10,000 "lines" or 90KB. I don't want to make a strongly typed object(s) for all the contents of this one json response just so I can run it through a deserializer - so that is out.
So the basic logic in my controller is:
Call externall api
Store string result of web request into a var (see json_string above)
Output those results as json (not a string) using the JsonResult producing method Json()
Any help is greatly appreciated... mind is melting.

The whole point of the Json() helper method is to serialize as JSON.
If you want to return raw content, do that directly:
return Content(jsonString, "application/json");

public ActionResult Test()
{
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}

Related

C# JObject arrives to the front as an empty list [duplicate]

This question already has an answer here:
JSON Objects are serialized to empty brackets when returned using JsonResult
(1 answer)
Closed 1 year ago.
I'm using jQuery Ajax to send a Newtonsoft object from a MVC controller task to the front, but I have been struggling a lot with it. For some reason the object arrives as an empty list I tried to simplify the object thinking that the problem was the structure nesting other objects, but it doesn't work even in the most simple case.
I updated the version of Newtonsoft as said in this other question Nested JObjects getting serialized as empty arrays but my problem persist. I know it looks easy but I'm not sure what I may be doing wrong.
Here is the method in the controller
[HttpPost]
public async Task<JsonResult> Something(string data)
{
//some asynchronous stuff
var jsonObject = new JObject();
jsonObject.Add("x", "text");
return Json(jsonObject);
}
My JQuery ajax call
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(parameters),
contentType: "application/json",
success: function (data) {
debugger;
}
}).fail(function (jqXHR, textStatus, errorThrown) {
});
And the answer arrives as somethign like this
[[[]]]
I'm going crazy with this problem any suggestions are really apreciated
I can' t see any async in your code, but in any case try this. And it is better to use ActionResult that JsonResult. In both cases json will be returned, but ActionResult allows to return bad request if there are some problems
public async Task<ActionResult> Something()
{
if(some promble) return BadRequest("problem");
return Ok( new { x="text"} );
}
I add an aswer to my own question hoping that it may help someone else in the same situation.
I wrapped the answer in the following manner and now it works fine. I'm not sure why it's not possible to send it directly but maybe is related to a problem on the nested objects.
JsonResult data = new JsonResult();
data.Data = new
{
success = true,
result = JsonConvert.SerializeObject(rta.Data)
};
Also may be useful to be careful with the maxlength of the strings because that may add more problems if the original object is too big.
If the object is not that big this may be a better alternative as noted by JSON Objects are serialized to empty brackets when returned using JsonResult

Angular/C# null body sent for POST

I've trying to do a POST in Angular, which makes a call to my C# backend. One API call works fine, but the other one doesn't exactly. I'm having a hard time figuring out what's going on, but I see that when I open the Network window in my browser's DevTools, the request payload has the JSON populated just fine. But in C#/the backend, it receives a null object, and I get a 200 code/null response from the call.
I've got the following code in Angular:
item.service.ts
private readonly _api = '...'
private postOptions = { headers: { 'Content-Type': 'application/json; charset=utf-8' }};
public addItem(formGroup: formGroup, isInactive: boolean): Observable<Item> {
let api = ``;
// These require different API calls depending on the flag
if (isInactive)
api = `${this._api}/AddInactiveItem`;
else
api = `${this._api}/AddItem`; // This one is the one having issues
const body = ItemPost.parse(formGroup.value);
return this.http.post<Item>(api, body, this.postOptions).pipe(
this.handle(
"POST successful",
"Error with POST"
)
);
}
item-post.ts
export class ItemPost {
Name: string;
Inactive: string;
...
public static parse(obj: any): ItemPost {
return !obj ? undefined : {
Name: obj.name,
Inactive: obj.inactive,
...
};
}
}
My backend/POST code is in C#. Both of my POST methods are built the exact same, but with different SQL calls.
[HttpPost]
public JsonResult AddInactiveItem([FromBody] ItemBody item)
{
if (!ModelState.IsValid)
return Json(null);
// Do SQL call for POST here, return JSON
}
[HttpPost]
public JsonResult AddItem([FromBody] ItemBody item) // This is where I have a breakpoint and it's passing in null
{
if (!ModelState.IsValid)
return Json(null); // And this is where I find myself
// Do SQL call for POST here, return JSON
}
JSON Payload (sorry, unable to get a screenshot but this is what I'm seeing):
{"Name":"Test", ..., "Inactive":"N"}
I think you are having problem with:
`$(this.api}/AddInactiveItem`
The right syntax for template strings is:
`${this.api}/AddInactiveItem`
I figured it out...and I feel dumb. Really dumb.
An int variable in Item was considered an optional int/number in the front-end for when an Item was considered active (not inactive), but in the backend, ItemBody didn't reflect that and was considered as just an int instead of int?. I had to dig through my ModelState errors through the debugger and it hinted this, but it's late at night and my mind didn't process it.
Gotta make sure all of the variable types are reflected properly in the Body object.

Failing to pass a very long string as parameter in an ajax call to an asp.net controller

In my api controller, I need to pass two parameters: an integer + a string. This string is a json variable so it's a very long string, I can't pass as part of the URL.
I tried passing it as POST parameter (in the data attribute of the ajax call), but I get an error: only the first parameter is read, so the URL passed is not the right one.
How should I do this?
EDIT
JS code:
function SavingFloor(FloorId, Json) {
$.ajax({
beforeSend: function (xhr) {
xhr.setRequestHeader('verifySession', verifySession());
xhr.setRequestHeader('Authorization', '#HttpContext.Current.Session["BaseAuth"]');
},
url: "/api/Floor/SaveFloor?FloorID=" + FloorId, //api: error in decoding json (the json can't be passed as parameter)
type: "POST",
data: {
jsonstring: Json
},
dataType: 'text/html',
success: function (data) {
alert('success');
}
});
}
Controller:
[HttpPost]
public void SaveFloor(int floorID, string jsonstring)
{
Floor floor = db.FloorSet.Find(floorID);
JavaScriptSerializer ser = new JavaScriptSerializer();
Dictionary<string, object> dict = ser.Deserialize<Dictionary<string, object>>(jsonstring);
floor.SavedJson = jsonstring;
floorRepository.Update(floor);
floorRepository.Save();
}
You could try adding [FromUri] and [FromBody] attributes to the SaveFloor method. You can send floorID in regular GET and send the long jsonstring as the POST body. Currently, Web API can only read a single parameter from a POST body. You either need to encapsulate both variables in a single object, or try this:
public void SaveFloor([FromUri]int floorID, string jsonstring)
You don't need to specify [FromBody] to jsonstring as it's the default one in a POST request.
After this, don't forget to change your client-side code to send the floorID in the query string too.

why do I have to match the parameter name to get json data from ajax call in MVC4 web app?

I just want to know why it's necessary for .NET to match parameter name with the JSON object's key name?
Quick code preview here...
var json = {
"service": "COMMON",
"method": "MENU_SUBLIST",
"UID": "1000007",
"ULID": "stackoverflow",
"UNM": "queston",
"SITE": "1",
"DEPT": "2",
"LANG": "ko",
"MENUID": "0000",
"STEPMENU": "",
"ACTIONNAME": ""
}
Okay, Let's call an action in a controller through Ajax.
$.ajax({
type: "POST",
url: "DATACRUD.json",
data: JSON.stringify(json),
contentType: "application/json; charset=utf-8",
dataType: "json",
async: false, //_async,
success: function (result) {
}
});
And my c# action code here..
[HttpPost]
public ActionResult DATACRUD(string jsondata)
{
return Json(new{ fromMVC = jsondata});
}
// Just example.
jsondata is here null because I didn't match the key name.
For DATACRUD to get the JSON data, I have to do like this.
{ jsondata : {
"service":"COMMON",
"method":"MENU_SUBLIST",
"UID":"1000007",
"ULID":"stackoverflow",
"UNM":"queston",
"SITE":"1",
"DEPT":"2",
"LANG":"ko",
"MENUID":"0000",
"STEPMENU":"",
"ACTIONNAME":""
}
}
Here question No.1 Why do I have to match the key name with the param name?
It just does? there's gotta be a reason, and I want to know why.
And what I want to do is...
{
"service":"COMMON",
"method":"MENU_SUBLIST",
"UID":"1000007",
"ULID":"stackoverflow",
"UNM":"queston",
"SITE":"1",
"DEPT":"2",
"LANG":"ko",
"MENUID":"0000",
"STEPMENU":"",
"ACTIONNAME":""
}
to pass this JSON data into the action, DATACRUD I specified above
I want DATACRUD action to take the JSON data and consume it whatever the key name is.
There's another answer for this. The answer is to create a model for JSON data and receive it as a model type, and get the model as string.
But defining models cannot be possible in my apps. It could cause a hundred of model creation.
So receiving the JSON data after making a model is the last thing I need.
In this case, how am I supposed to do?
No key name matching is allowed.
No generating model is allowed.
No third party framework is allowed.
I think the possible answers narrow down to a few....
What I have to do?
The MVC routing engine dictates that the parameter names must match, as that is how it knows what to populate since everything comes through as strings to the server. The MVC plumbing will be searching through the query portion of the URL, and even searching fields in a form on a POST to populate all of your parameters.
Having a hundred models is not that bad for a complex project. However, it can be a pain if you have to go back and retrofit your entire application.
No matter what you do, you'll need to make sure that your JavaScript variable names match those of your Action method parameters, which shouldn't be a problem since you're writing both sides.
Base on post MVC controller : get JSON object from HTTP body?
You action should be:
[HttpPost]
public ActionResult DATACRUD()
{
Stream req = Request.InputStream;
req.Seek(0, System.IO.SeekOrigin.Begin);
string json = new StreamReader(req).ReadToEnd();
return Json(new { fromMVC = json });
}

No action was found that matches the request URI

I have attempted to modify one of my api controller to allow for the creation of multiple reservations by allowing one of the parameters to be passed in as a pipe delimited string. The method and class can be seen here:
public class ReservationsController : ApiController
{
public HttpResponseMessage PostReservation(string eRaiderUserName, string SpaceNumbers)
{
char[] delimiter = { '|' };
string[] spaces = SpaceNumbers.Split(delimiter);
bool saved = true;
foreach(string space in spaces)
{
var reservation = new Reservation { eRaiderUserName=eRaiderUserName, SpaceNumber=Convert.ToInt32(space) };
if (true)
{
reservation.Game = db.Games.FirstOrDefault(g => g.ID == AppSettings.CurrentGameID);
db.Reservations.Add(reservation);
db.SaveChanges();
//HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, reservation);
//response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = reservation.ID }));
//return response;
}
else
{
saved = false;
//return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
db.SaveChanges();
if (saved)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = 1 }));
return response;
} else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
}
I have a form that posts what I think should be the right information, but I keep getting this error:
{"$id":"1","Message":"No HTTP resource was found that matches the request URI 'http://localhost:58463/api/Reservations'.","MessageDetail":"No action was found on the controller 'Reservations' that matches the request."}
The (modified) save method in the api is still definitely a work in progress. But what is keeping this from finding the web api controller? Here is the firebug output:
As pointed out, the problem is that a POST action can only transfer the data posted in the body to a single object (for technical reasons).
That means that you can get data from the route data, from the querystring, and from the body, with the following limitations:
data from querystring or route data must be single values (i.e. they cannnot be classes), in any number
you can have only one parameter of the action with data coming from the request body, but this can be a complex class
you can make any combination of this, i.e. a single or complex param coming from the body, and any number of single parameters coming from the route data or the querystring.
So, the most generic way to solve your problem (i.e. that can be easyly applied to other classes where you need to pass complex data, even more complex than this case) is this:
First, make a class which has properties for all the needed data,in your case:
public class ReservationData
{
public string eRaiderUserName { get; set; }
public string SpaceNumbers { get; set; }
}
Second, use this class as the type of the received parameter in your action:
public HttpResponseMessage PostReservation(ReservationData reservationData)
With this code the formatter can map all the data in the request body to a single parameter in the action. You can use JSON or formdata formats, like the generated by jQuery.
NOTE: the property names must case-sensitively match the name of the posted parameters.
This is because you send x-www-form-urlencoded data to controller, to handle this data you must use [FromBody] before parameter like
public HttpResponseMessage Post([FromBody] string name) { ... }
but this approach has a lot of limitation:
1) There can be only one parameter marked [FromBody] attribute (it can be complex type)
2) The data must be encoded as =value not as key=value .
You can read it here description and how make it work here example .
If it possible i recommend you to send Json data to controller, without this limitation.
Web API has limited support to map POST form variables to simple parameters of a Web API method. Web API does not deal with multiple posted content values, you can only post a single content value to a Web API Action method.
public HttpResponseMessage PostReservation(string eRaiderUserName, string SpaceNumbers)
{ //...}
and you are trying to call using jQuery:
$.ajax({ url: 'api/reservations', type: 'POST', data: { ... }, dataType: 'json', success: function (data) {alert(data);} });
Unfortunately, Web API can’t handle this request and you’ll get error. But if you pass parameters using query string, It’ll work:
$.ajax({ url: 'api/reservations?eRaiderUserName=2012&SpaceNumbers=test', type: 'POST', dataType: 'json', success: function (data) { alert(data); } });
But it’s not good solution and not applicable for complex objects. So here are the different ways to do it.
Using Model Binding (Preferred)
Using Custom Parameter Binding
FormDataCollection
Query String

Categories

Resources