Error using dynamic keyword in asp.net mvc 4 - javascript

I am getting this long error when i accpet the parameter as dynamic on my server side action method in mvc 4.
{"Message":"An error has
occurred.","ExceptionMessage":"'Newtonsoft.Json.Linq.JObject' does not
contain a definition for
'TournamentId'","ExceptionType":"Microsoft.CSharp.RuntimeBinder.RuntimeBinderException","StackTrace":"
at CallSite.Target(Closure , CallSite , Object )\r\n at
System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite
site, T0 arg0)\r\n at
ManagerDeTorneos.Web.Controllers.TournamentDateController.Create(Object
data) in
F:\Prince\Projects\Juan\trunk\ManagerDeTorneos.Web\Controllers\TournamentDateController.cs:line
133\r\n at lambda_method(Closure , Object , Object[] )\r\n at
System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c_DisplayClass13.b_c(Object
instance, Object[] methodParameters)\r\n at
System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object
instance, Object[] arguments)\r\n at
System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1
func, CancellationToken cancellationToken)"}
[HttpPost]
public HttpResponseMessage AddMatch(dynamic data)
{
int tournamentDateId = (int)data.TournamentDateId.Value;
var tournamentDate = Catalog.TournamentDateRepository.GetById(tournamentDateId);
if (tournamentDate == null)
{
throw ExceptionHelper.NotFound("Fecha no encontrada!");
}
In The above method data Contains tournamentId as sent from ajax call as JSON.Stringify({'TournamentId':'5'}).
Can anybody tell me what is the cause of error. I even replaced the dll of Newtonsoft.Json as well

You are right dan but i fixed my issue by removing that dll from GAC. May be in GAC it was using old assembly

The error is caused by the fact that you typed your parameter as dynamic, which means that the model binder doesn't know what to make it. It's the same as if you were to declare it as an object. Since you are providing JSON, it serializes the object as a Json.Net JObject. Just because you define it as a dynamic doesn't mean that it's going to magically take whatever shape you need it to.
Change it to a concrete type - something that matches the structure of the provided JSON:
public class TournamentInfo
{
public int TournamentId { get; set; }
}
[HttpPost]
public HttpResponseMessage AddMatch(TournamentInfo data)
{
int tournamentDateId = data.TournamentId;
var tournamentDate = Catalog.TournamentDateRepository.GetById(tournamentDateId);
if (tournamentDate == null)
{
throw ExceptionHelper.NotFound("Fecha no encontrada!");
}
This way, the binder knows what it's supposed to turn the JSON into, and since TournamentInfo matches the structure of the JSON, it won't have any trouble serializing it.
Don't misuse dynamic. It was not introduced into C# so developers could stop defining classes.

Related

How can I access parameters from a POST (or other HTTP) request in a C# server?

I'm building a Reactjs application using ASP.Net Core, and I'm completely new to this. I have a JS component that (to the best of my knowledge) is making an appropriate fetch request (POST) to a C# server controller. The server is definitively receiving the request. However, I have absolutely no idea how to access the parameters of the request (which I am passing through the body).
I've tried using [FromBody] to access the body directly. I've also tried to utilize the Request.Body, the Request.Form, the Request.Query, the Request.Params, etc. I've attempted to follow the guidelines I've found online that seem to try to address my problem. Several of them flat-out haven't worked. Most of them are using key words, classes, etc. that are not available to me in my current libraries, and they don't list the appropriate libraries. For all I know, I've stumbled across the right answer already. But for someone like me with a highly logical mind but also pretty much zero experience in the field, I can't wrap my mind around any of it.
My POST request using fetch in JavaScript:
fetch('api/Database/PushStatus',
{
method: 'post',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify({ order: this.state.orderNum, status: this.state.newStatus })
}
).then(response => {
response.json().then(data => {
this.setState({ reqCheck: "" + response, didPush: false });
})
}).catch(err => {
this.setState({ reqCheck: "Failure! (js)", didPush: false })
});
And my request handling on my C# server:
[Route("api/[controller]/[action]")]
public class DatabaseController : Controller
{
string conStri = "Data Source=ADM293\\MSSQLSERVER01;Initial Catalog=testDB;User ID=sa;Password=password.1";
SqlConnection cnct = null;
[HttpPost]
public void PushStatus(string order, string status)
{
cnct = new SqlConnection(conStri);
SqlCommand command = new SqlCommand("insert into testTable values ('" + order + "', '" + status + "');", cnct);
using (cnct)
{
cnct.Open();
int result = command.ExecuteNonQuery();
cnct.Close();
}
}
}
I would like my server to be updated with the contents of this.state.orderNum and this.state.newStatus.
Instead, my server is updated with empty string values (which makes perfect sense).
You can create a class that represents the request:
public class PushStatusRequest
{
public string Order { get; set; }
public string Status { get; set; }
}
And use it like this:
[HttpPost]
public void PushStatus([FromBody] PushStatusRequest request){
//request.Status
//request.Order
}
#Anteo is right. But I would like to add some explanation.
You have faced two different ways to pass params to a controller.
You try to use a body (setting body in request) as an entrance and the query (in the controller) as an output.
Well, body is one type and it requires to be some model on a Controller side. Use [FromBody] to automatically retrieve your data from a request into a model. Create this model as a separate class following the same naming politics (ignoring case).
Then, a query string is what you are using at the controller side. On a request side, it follows the URL like this: https://host:port/route/to/then/query/params. So, if I am not mistaking a base URL is a part https://host:port. Everything is left is a query string. A part of that is being mapped to the route to your controller's action. Anything left is interpreted as useful info and mapped to an action params.
So, here is the moment for you to choose (depending on the length of your orderNum and newStatus) which approach to use. I would recommend using the body as it is more data than routing.
Also, If you inherit [ControllerBase][1], then you can use Request property in action to access the request itself. But be careful here.
P.S. I would recommend you to read more about requests, things like form data, body, queries, etc.
If have any further questions feel free to ask.
By default, capitalization changes between JavaScript and C#. So, you probably just need to change your method signature:
public void PushStatus(string Order, string Status)
That said, having the class the way #Anteo suggested is usually better. Also, I assume you put SqlConnection just for clarity. You shouldn't do it in the controller

JQuery Javascript function to return highchart graph data source in JSON and formatted correctly through Selenium and C#

I am trying to figure out how to get the JSON equivalent of a highchart graph returned to me using Selenium and C#. I got pretty far, but I am hitting a couple issues. For the specific highchart, perform the following steps:
Go here https://rcpsc.releasecandidate-community360qa.net/login.aspx?action=enablelogin
Login with: uw_lr1/test
The chart will show on the next page once you login. The ID of the chart element is "EPAChart"
Issue #1
I can use the below function in the Console tab of DEV tools to retrieve the data in JSON format, but it does not organize it correctly (it lists all EPA's first, then all values of those EPAs second) JSON.stringify(angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData']);
When I plug this into Visual Studio with C# and Selenium and then try to convert this to a DataTable, it does not allow me because the data is not organized correctly. For a similar issue, see : Newtonsoft.Json JsonConvert To Datatable
using Newtonsoft.Json;
using OpenQA.Selenium;
string jsText = string.Format("return JSON.stringify(angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData']);")
var jsResult = driver.ExecuteScript(jsText) as string;
JsonConvert.DeserializeObject<DataTable>(jsResult);
Issue #2
I have a Javascript/Jquery function which produces the JSON organized correctly, but I dont know how to call it using Selenium/C#. The code, driver.ExecuteScript, does not like this function, I guess because it is too complicated and uses variables, so driver.ExecuteScript (IJavaScriptExecutor->ExecuteScript) throws an exception. Here is the function:
var epadatasource = []; for(var i=0;i<angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Categories.length;i++){epadatasource.push({category: angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Categories[i], data: angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Data[i]}); }; JSON.stringify(epadatasource);
For Issue #2, how do I call the above function in C#/Selenium so that it doesnt throw an exception and instead returns my JSON? Or for issue #1, is there a workaround to organize that JSON correctly?
I figured out a workaround for issue #1 and #jeffC provdided the solution to issue #2
Issue 1 resolution is to add JSON to C# object, then convert it to a new object, and deserialize it for a fixed JSON:
public static string TransformJSON(string json, IWebElement chartElem)
{
string fixedJson = "";
if (chartElem.GetAttribute("id") == "EPAChart")
{
dynamic obj = JsonConvert.DeserializeObject<EPAObservationCountOriginal>(json);
List<EPAObservationCountFixed> fixedObject = new List<EPAObservationCountFixed>();
for (int i = 0; i < obj.Categories.Length; i++)
{
fixedObject.Add(new EPAObservationCountFixed() { category = obj.Categories[i], data = obj.Data[i] });
}
fixedJson = JsonConvert.SerializeObject(fixedObject);
}
return fixedJson;
}
#endregion methods
#region Class objects representing graphs
public class EPAObservationCountFixed
{
public string category { get; set; }
public string data { get; set; }
}
public class EPAObservationCountOriginal
{
public string[] Categories { get; set; }
public string[] Data { get; set; }
}
Issue 2 resolution is to add the word "return" in the function:
var epadatasource = []; for(var i=0;i<angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Categories.length;i++){epadatasource.push({category: angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Categories[i], data: angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Data[i]}); }; return JSON.stringify(epadatasource);

Bind array of complex objects in GET request - jquery.param() traditional flag

I'm trying make a jquery.ajax call to the following controller action:
public ActionResult Handler(SemanticPart[] semanticParts, string first, string last)
I have the following data JSON object with the corresponding server side model having public { get; set; } properties:
var data = {
semanticParts: [{ hasLabel: "label", hasType: "type", hasIndex : 0 }],
first: "first",
last : "last"
};
The problem is jQuery.param seems to have no serialization option for the default MVC model binder.
decodeURIComponent($.param(data)) produces:
"semanticParts[0][hasLabel]=label&semanticParts[0][hasType]=type&semanticParts[0][hasIndex]=0&first=first&last=last"
while setting the traditional flag like so decodeURIComponent($.param(data, true)) produces:
"semanticParts=[object+Object]&first=first&last=last"
MVC's default model binder for complex arrays needs the following to bind correctly (tested in Fiddler Composer):
"semanticParts[0].hasLabel=label&semanticParts[0].hasType=type&semanticParts[0].hasIndex=0&first=first&last=last"
Which simply used: array[0].property= instead of array[0][property]=
I understand there's no universal specification for param strings agreed-upon by all web frameworks but why jQuery.param with traditional flag set true returns a [object+Object] is beyond me... that is absolutely useless in any framework.
It there any way to patch this?
Perhaps a regex to replace the pattern [#][text] with [#].text? (actually the encoded version of this is more relevant)
You should implement a model to hold this parameters:
public class SemanticPartViewModel
{
public List<SemanticPart> semanticParts { get; set;}
public string first { get; set; }
public string last { get; set;}
}
And change the controller to receive this as parameter
public ActionResult Handler(SemanticPartViewModel semanticParts)
{
/*Do stuff*/
}
You should use JSON.stringify(mydata) as well to create the data for the $.ajax call
This way the default modelbinder will take care about the rest.

Assign new values in a Breeze entity

I'm developing a spa web application with BreezeJS and the DurandalJS Framework. I came accross a problem which I can't fix.
I have a entity called: Car, this entity contains name, number, owner, type en manufacturer. In this entity the name and number are filled in as the entity is created AND saved in the database. The other properties are allowed to be NULL.
This because the other values are filled in during a modal/ dialog screen. Here a user can select a owner from a list and also a type and manufacturer from a list. When the user selects one from a dropdown the selected value should be assigned to the value of the Car entity. How can I get this to work?
Car().Owner = newOwner;
Car.Owner() = newOwner;
This won't work. I tried a lot of combinations. Remember that the value was null first and that I can't insert a new value;S
Edit 1
Here the Entity Framework model of Car
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Estimate_App.Models
{
public class tblCar
{
[Key]
public int CarID { get; set; }
public string CarNumber { get; set; }
private DateTime _CreationDate;
public DateTime CreationDate
{
get { return this._CreationDate; }
set { this._CreationDate = DateTime.Now; }
}
//This is the Owner
[ForeignKey("Owner")]
public int? OwnerID { get; set; }
public tblOwner Owner { get; set; }
}
}
Here is what I put in my Car().Owner(), consider Container should be Car (this is an other project with the same problem)
I hover my mouse over newValue.
Edit 2
By a answer of Julián Yuste I also tried this but it didn't work. Here is the error:
When I do Container().Owner(newValue);
Edit 3
The code that fetches the owners
breeze.EntityQuery.from("Customers")
.using(dataservice.manager)
.execute().then(function (data) {
data.results.forEach(function (item) {
tempCustomerList.push(item); //ko.observableArray([]);
});
}).fail(function (data) {
});
Are you using the EntityManager from your dataservice object in order to create the newOwner object?
In other words, you probably shouldn't be doing this*:
var newOwner = new Owner();
newOwner.OwnerID = 123;
You should do this:
var newOwner = dataservice.manager.createEntity('Owner', { OwnerID: 123 });
*Note that can actually use new Owner(), but that requires you to define entity constructors in your code. :-)
For more information, check out the Breeze documentation: http://www.breezejs.com/documentation/creating-entities
Also, note that you can read the Breeze JavaScript code to help you understand the issue. If you search breeze.debug.js for your error message (An Entity cannot be attached to an entity in another EntityManager. One of the two entities must be detached first.), you will find the line of code that is causing the exception. It may be helpful to backtrack from there.
Edit
The answer to the question was to make sure that the EntityManager object is a Singleton (in this case, the dataservices.manager object).
In other words, use the same EntityManager object to update objects as you use to query for objects.
I think we need more information. Is the 'Owner' property an instance of another entity or is it a primitive type, i.e. string, number etc?
If it is an entity then I would first check that your 'newOwner' variable was also in fact an entity.
If owner is an observable, you need to asign the new value as: owner(newOwner).
Greetings.

JSON representation of a list of keyvaluepairs

I have an MVC JSON controller method that I call from frontend. It looks like this:
public JsonResult FacetedSearch(string searchString, List<KeyValuePair<string,string>> facets)
I'm calling it via jQuery ajax at the frontend, I'm serializing the data in the following manner:
JSON.stringify({searchString: "the matrix", facets: [{Key: "TypeName", Value: "Feature Film"}, {Key:"TypeName", Value:"Series"}]}
When I debug through my application code, I see that searchString gets passed successfully over to the MVC method, but the variable facets gives me a list of 2 KeyValuePairs with null Key and Value.
I've looked at my serialization and it seems valid but for whatever reason it isn't going over to my application correctly. What gives?
Rather than expect two objects in your signature, it would make more sense to expect a single object that contains both of your parameters. This would be something like the following.
public JsonResult FacetedSearch(RequestObject requestObject)
{ }
public class RequestObject
{
public string searchString { get; set; }
public List<KeyValuePair<string,string>> facets { get; set; }
}
This way, when you send your JSON object, the signature is an object with two properties, just like the object that you are sending.
Per Is there a serializable generic Key/Value pair class in .NET?
I found out why it's not serializing it. Apparently it's unserializable.

Categories

Resources