accessing dynamic property when calling Action....MVC - json

I have an Action method that returns JSON, for brevity, I excluded code. :
public ActionResult SetMasterLocation(string masterValue)
{
json = new JavaScriptSerializer().Serialize(masterLocation);
return Json(json, JsonRequestBehavior.AllowGet);
}
I need to call this method and access the JSON string that gets returned:
var jVendors = SetMasterLocation(masterValue);
When I run it and inspect the output, I see the JSON string in a dynamic property called Data:
But if I try to access data like this, the app will not compile because the compiler says Cannot resolve symbol 'Data':
var jVendors = SetMasterLocation(masterValue);
var data = jVendors.Data;
How do I access the Data property at runtime?

Return JsonResult
return new JsonResult()
{
Data = someData,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
Then, you can access Data property of the result

Related

How can I send custom object from my callable Firebase Cloud Function in TypeScript to my Unity app?

I'm trying to use Firebase and its callable Cloud Functions for my Unity project.
With the docs and different posts I found on the web I struggle to understand how returning data works. (I come from Azure Functions in C#)
I use TypeScript, and try to return a custom object CharactersResponse:
export class CharactersResponse //extends CustomResponse
{
Code!: CharactersCode;
CharacterID?: string;
}
export enum CharactersCode
{
Success = 0,
InvalidName = 2000,
CharacterNameAlreadyExists = 2009,
NoCharacterSlotAvailable = 3000,
InvalidCharacterClass = 4000,
EmptyResponse = 9000,
UnknownError = 9999,
}
(Custom Response is a parent class with only an UnknownErrorMessage string property, that I use for adding extra message when needed, but only in Unity. I don't need it in my functions.)
I have the same in my C# Unity Project:
public class CharactersResponse : CustomResponse
{
public CharactersCode Code;
public string CharacterID;
}
public enum CharactersCode
{
Success = 0,
InvalidName = 2000,
CharacterNameAlreadyExists = 2009,
NoCharacterSlotAvailable = 3000,
InvalidCharacterClass = 4000,
EmptyResponse = 9000,
UnknownError = 9999,
}
I'm still learning but I found it useful to do this way for displaying correct messages in Unity (and also regarding localization).
When the Code is 0 (Success), I will usually need to get some data at the same time like in this example CharacterID, or CharacterLevel, CharacterName etc.. CharacterResponse will be used for all functions regarding Characters like "GetAllCharacters", "CreateNewCharacter" etc..
My Function (CreateNewCharacter) looks like this:
import * as functions from "firebase-functions";
import { initializeApp } from "firebase-admin/app";
import { getFirestore } from "firebase-admin/firestore";
import { CharactersResponse } from "./CharactersResponse";
import { CharactersCode } from "./CharactersResponse";
import { StringUtils } from "../Utils/StringUtils";
// DATABASE INITIALIZATION
initializeApp();
const db = getFirestore();
// CREATE NEW CHARACTER
export const CreateNewCharacter =
functions.https.onCall((data, context) =>
{
// Checking that the user is authenticated.
if (!context.auth)
{
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
}
// TEST
data.text = '';
// Authentication / user information is automatically added to the request.
const uid: string = context?.auth?.uid;
const characterName: string = data.text;
// Check if UserID is present
if (StringUtils.isNullOrEmpty(uid))
{
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'Missing UserID in Auth Context.');
}
const response = new CharactersResponse();
if (StringUtils.isNullOrEmpty(characterName))
{
response.Code = CharactersCode.InvalidName;
console.log("character name null or empty return");
return response; // PROBLEM IS HERE *****************
}
console.log("end return");
return "Character created is named : " + characterName + ". UID = " + uid;
});
In Unity, the function call looks like this:
private static FirebaseFunctions functions = FirebaseManager.Instance.Func;
public static void CreateNewCharacter(string text, Action<CharactersResponse> successCallback, Action<CharactersResponse> failureCallback)
{
Debug.Log("Preparing Function");
// Create the arguments to the callable function.
var data = new Dictionary<string, object>();
data["text"] = text;
// Call the function and extract the operation from the result.
HttpsCallableReference function = functions.GetHttpsCallable("CreateNewCharacter");
function.CallAsync(data).ContinueWithOnMainThread((task) =>
{
if (task.IsFaulted)
{
foreach(var inner in task.Exception.InnerExceptions)
{
if (inner is FunctionsException)
{
var e = (FunctionsException)inner;
// Function error code, will be INTERNAL if the failure
// was not handled properly in the function call.
var code = e.ErrorCode;
var message = e.Message;
Debug.LogError($"Code: {code} // Message: {message}");
if (failureCallback != null)
{
failureCallback.Invoke(new CharactersResponse()
{
Code = CharacterCode.UnknownError,
UnknownErrorMessage = $"ERROR: {code} : {message?.ToString()}"
});
}
}
}
}
else
{
Debug.Log("About to Deserialize response");
// PROBLEM IS HERE *********************
CharactersResponse response = JsonConvert.DeserializeObject<CharactersResponse>(task.Result.Data.ToString());
Debug.Log("Deserialized response");
if (response == null)
{
Debug.LogError("Response is NULL");
}
else
{
Debug.Log("ELSE");
Debug.Log($"Response: {response}");
Debug.Log(response.Code.ToString());
}
}
});
}
The problem :
In my Unity C# code, task.Result.Data contains the CharactersCode I've set in my function, but I can't find a way to convert it to CharactersResponse. (It worked in Azure Functions). Moreover, the line just after Deserialization Debug.Log("Deserialized response"); is not executed. The code seems stuck in the deserialization process.
I tried with and without extending my TypeScript class with CustomResponse(because I don't need it in my Function so I didn't extended it at first).
I also tried setting a CharacterID because I thought maybe it didn't like the fact that this property was missing but the result is the same.
I don't understand what is the problem here? If any of you can help.
Thanks.
HttpsCallableResult.Data is of type object!
=> Your ToString will simply return the type name something like
System.Object
or in your case the result is a dictionary so it prints out that type.
=> This is of course no valid JSON content and not what you expected.
Simply construct the result yourself from the data:
var result = (Dictionary<string, object>)task.Result.Data;
CharactersResponse response = new CharactersResponse
{
Code = (CharactersCode)(int)result["Code"],
CharacterID = (string)result["CharacterID"];
};
I wanted to implement derHugo's solution but couldn't find a way to convert task.Result.Data to Dictionary<string, object>.
The code was stuck at var result = (Dictionary<string, object>)task.Result.Data; even in step by step debugging and no error popped up.
OLD SOLUTION:
So I did a little research and stumbled upon this post and ended up using this instead :
var json = JsonConvert.SerializeObject(task.Result.Data);
CharactersResponse response = JsonConvert.DeserializeObject<CharactersResponse>(json);
I basically convert the task.Result.Data to JSON and convert it back to CharactersResponse and it works. I have what I wanted.
However, I seem to understand that it is not the best solution performance-wise, but for now it is okay and I can now move forward in the project, I'll try to find a better solution later.
NEW SOLUTION:
I wanted to try one last thing, out of curiosity. I wondered what if I convert to JSON at the beginning (in my function) instead of at the end (in my Unity app). So I did this in my function's TypeScript code:
response.Code = CharactersCode.InvalidName;
var r = JSON.stringify(response); // Added this line
return r; // return 'r' instead of 'response'
In my C# code, I retried this line of code:
CharactersResponse response = JsonConvert.DeserializeObject<CharactersResponse>(task.Result.Data.ToString());
And it works ! I just needed to convert my object to JSON in my function before returning it. It allows me to "save" one line of code to process on the client side compared to the old solution.
Thanks derHugo for your answer as it helped me finding what I want.

How to access JSON?

I am wrote API method, after calling that method , I got my response like
[
{
"spark_version": "7.6.x-scala2.12"
}
]
Now I want to have variable in my API method which store value 7.6.x-scala2.12.
API Controller method
[HttpGet]
public IActionResult GetTest(int ActivityId)
{
string StoredJson = "exec sp_GetJobJSONTest " +
"#ActivityId = " + ActivityId ;
var result = _context.Test.FromSqlRaw(StoredJson);
return Ok(result);
}
So how this variable should call on this response to get string stored in spark_version?
Thank you
As you have the JavaScript tag, here's how you'd do it in JS:
If you are able to call your API method, then you can just assign the response to a variable. For example, if you are calling it using the fetch API, it would look something like:
let apiResponse;
fetch('myApiUrl.com').then((response) => {
if (response.status === 200) {
apiResponse = response.body;
console.log('Response:', apiResponse[0]['spark_version']);
}
});
(I defined the variable outside the then to make it globally accessible)

Access JSON Object Prop - Angular JS

First time using Angular JS, I'm using $http.get to return a Json object. When I output the response data, I can see entire JSON object in the console, but I can't access the object or properties. What am I missing here?
$scope.init = function (value) {
$scope.productEditorModel.productId = value;
$scope.loadData($scope.productEditorModel.productId);
}
$scope.loadData = function (productId) {
var responsePromise = $http.get("/Product/GetProductModel", {
params: { productId: productId }
});
responsePromise.success(function (dataFromServer, status, headers, config) {
console.log(dataFromServer.DataModel);
});
};
When I first output the dataFromServer to the console, the object is null and then it becomes populated. Since it's an async call, I should be able to access and set whatever vars inside the success
I would like to be able to directly access the object and property names IE:
$scope.productModel.productId = dataFromServer.Data.productId
My json looks like this:
Object{DataModel:Object, IsSuccess: false}
Thanks!
The problem is that you are trying to access the data before it comes back. Here is a plunker that demonstrates how to set it up, and how not to.
//predefine our object that we want to stick our data into
$scope.myDataObject = {
productId: 'nothing yet',
name: 'nothing yet'
}
//get the data, and when we have it, assign it to our object, then the DOM will automatically update
$http.get('test.json')
.success(function(data) {
$scope.myDataObject = data
});
var y = $http.get('test.json')
//this throws an error because I am trying to access the productId property of the promise object, which doesn't exist.
console.log(y.productId);
Here is the demo

Entity object fails when converting to JSON

I have been trying to get an Entity Framework model to convert to JSON to display in a web page. The Entity object is created fine but something fails when it is returned. Below is the code from my ASP.NET Web API project. By setting a breakpoint I can see the object collection is created just fine.
public class ClientsController : ApiController
{
public IEnumerable<Client> GetAllClients()
{
using (var context = new MyClientModel.MyEntities())
{
var query = context.Clients.Where(c => c.State == "CA");
var customers = query.ToList();
return customers;
}
}
}
Here is the HTML/Javascript code I use to call the ASP.NET Web API
<script>
var uri = 'api/clients';
$(document).ready(function () {
// Send an AJAX request
$.getJSON(uri)
.done(function (data) {
// On success, 'data' contains a list of products.
alert('Made it!'); // ** Never reaches here **
$.each(data, function (key, item) {
// Add a list item for the product.
$('<li>', { text: item }).appendTo($('#clients'));
});
});
});
</script>
I use Fiddler to view the response and it returns a .NET error that says ...
The 'ObjectContent' type failed to serialize the response body for content type 'application/json; charset=utf-8'."
and the inner exception message is ...
Error getting value from 'Patients' on 'System.Data.Entity.DynamicProxies.Client
Patients is a related entity in my model but I am confused why it would be an issue as I am only returning Client objects.
I found a solution that works, though I admit I am not sure exactly how it works. I added the line context.Configuration.ProxyCreationEnabled = false; to my method that returns the object collection and all my objects were returned. I got the code from the following SO Question - WebApi with EF Code First generates error when having parent child relation.
public class ClientsController : ApiController
{
public IEnumerable<Client> GetAllClients()
{
using (var context = new MyClientModel.MyEntities())
{
context.Configuration.ProxyCreationEnabled = false; // ** New code here **
var query = context.Clients.Where(c => c.State == "CA");
var customers = query.ToList();
return customers;
}
}
}

Why Json() Function is unknown

I have the following code (in MVC3):
public JsonResult GetTown(string term)
{
db = new SHAMUTEntities1();
var data = db.towns.Where(t => t.name.Contains(term))
.Take(10)
.Select(t => new {label=t.name }).ToArray();
return Json(data, JsonRequestBehavior.AllowGet);
}
}
I get the following error:
System.Web.Helper.Json is a type but is used like a variable
Can anybody help with this.
thanks
Json is a method of the System.Web.Mvc.Controller class of ASP.NET MVC 3. Since it's not compiling, you are probably using it in a class that does not derived from Controller.
To fix it, just return the data instance from your method and convert it to JSON in a controller metod.