Create a manual property binder in c# - c#

I have a task I am trying to complete, and trying to do it the best way possible.
Let say I have a jObject
var jobj = {val1: 1, val2: "s"} // on server
and I need to user the properties in that object as the params for a Method.Invoke call.
someMethod.Invoke(class, params);
I need some way to take the properties from the JObject and convert them into an array of objects to pass to the invoke method.
I can easily get the param details
var param = Method.GetParameter("ParameterName");
this will give me the value, type be it a string or a complex object.
While a believe I could write the code to do this I think it would be better to use built in .Net functionality if it exists.
.Net does very similar conversions for all WEB_API and MVC Controller calls, and I would like to tap into those existing functions to do the work as they are probably very well vetted, but I am having trouble finding out how it is done.
I have found the IActionValueBinder and the DefaultModelBinder but I cannot figure out how to use these outside the context of a standard controller.

Related

Json object in post not recognized as object in web api

I have an angular client and want to execute a get request to my web api backend to get a list of items from the underlying Dapper Db Wrapper. Dapper allows me to pass in parameters as an anonymous object which would in csharp look like this:
connection.GetList<T>(new {myParam1:"a", myParam2: true});
What I want to achieve is, to create this parameter object in my angular frontend and pass it in a post request to the server which would then pass it on to the GetList function. The problem here is that the web api does not deserialize it as an (anonymous) object, but rather and IEnumerable of JTokens?
My web api signature is this:
public async Task<IHttpActionResult> MyFunction([FromBody]dynamic whereCond)
I have also tried to pass the object as string wrapped in an outer object like so (angular client):
this.migController.MigrationGetMigrationReports({whereCond: JSON.stringify({NotMigrated: true, MissingTargetFiles: 0})})
and then on the server I manually deserialize it as JObject:
string obj = whereCond.whereCond;
dynamic pObj = JObject.Parse(obj);
But this results in the exact same result: pObj is an IEnumerable and therefore I get an error message from the GetList call:
An enumerable sequence of parameters (arrays, lists, etc) is not allowed in this context
can anybody help?
The answer to my question turned out rather simple:
dynamic pObj = JObject.Parse(obj).ToObject<ExpandoObject>();
I had to cast it as ExpandoObject not just dynamic.
#Tsahi: this is not a design problem. My intention was to provide the server with parameters (filter) which is a quite common task for a client to reduce the dataset to be transferred. We could debate a standard way how to provide these parameters, however. In my special case the most practical way is the anonymous object.

Casting objects from jsonb to different objects

I am developing an ASP.NET Core API that uses events with MediatR to publish them in the system. I am looking to include a scheduling service to the Api where events are stored in a database and pull out later and published using MediatR.
The issue I have is that the objects are stored in the database as jsonb and I need to be able to draw them out and cast them to specific object types. I can store the name of the type in the database and access the type that way. However I can't find a solution to this online.
If there is a better way to do this who thing that would be helpful too, but I'm looking for a solution that looks something like this:
var eventType = Type.GetType("foo");
var eventObject = obj.ToObject<eventType>();
If there is a better way of doing this please let me know!
Thanks.
Assuming you could figure out a way to do this, how exactly do you intend to use eventObject after you've managed to create it? Its type is not known at compile time, so you can't write code that uses its methods and properties, because you don't know what methods and properties it has.
For example, if you have a "foo" type with a DoFoo() method and a "bar" type with a DoBar() method, how do you know whether to call DoFoo() or DoBar()?
var eventType = Type.GetType("foo");
var eventObject = obj.ToObject<eventType>();
eventObject.DoFoo(); //How do you know to do this?
eventObject.DoBar(); //How do you know to do this?
The best you can do is a series of if statements:
if (eventType) == typeof(foo))
{
eventObject.DoFoo();
}
if (eventType) == typeof(bar))
{
eventObject.DoBar();
}
Well, if you're going to do that, you may as well cast it in the same if block, which eliminates your problem.
if (obj.GetType() == typeof(foo))
{
((foo)obj).DoFoo();
}
if (obj.GetType() == typeof(bar))
{
((bar)obj).DoBar();
}
If you don't actually need any of its properties or methods, and only need to be able to pass it to some generic method, you can just pass it along as an object. Getting the method is a little tricky though:
mediatR.GetType()
.GetMethod("Publish");
.MakeGenericMethod(eventType);
.Invoke(obj, null);

What is the best way to serialize, return and consume complex C# object from an MVC3 app?

Here's my situation: I have an MVC3 app that has some very complex C# objects, and those get rendered to a views in this application. However, I have a new requirement: a console application (that I am also writing) will run under a scheduler, and it needs to pull these objects from this MVC3 app, and then do something else with these complex objects.
Since I have control over both apps, I can share a library of the complex objects between them. All of these objects are marked [Serializable]. However, I cannot figure out an easy way to serialize these objects and send them from the MVC3 app to the Console app.
I tried simple JavaScriptSerializer and using the HttpClient to read the string, then deserialize it on the console-app end of things, but unfortunately it doesn't deserialize the data correctly. Everything is null. I can inspect the string on a breakpoint when it arrives at the console app, and all the data is there, in the string, but it just doesn't get de-serialized correctly.
Is there an easier way to do this? I don't care what the serialization method is. The data doesn't have to be passed as JSON and no other application but mine is going to consume these objects. But so far I can't figure out the easiest way to produce/consume these objects.
I know I can go down the whole "create a web service contract" and use data annotations route, but I was hoping there was an easier, less time-consuming way of doing it.
Using Json.NET:
Server-Side
string serializedObject = JsonConvert.SerializeObject(yourComplexObject);
// Send the string to the client...
Client-Side
In the client, you don't even have to know the deserialized object's type, you can take advantage of anonymous objects and dynamic:
string serializedObject = // ... Fetch from server
dynamic complexObject = JsonConvert.DeserializeObject(serializedObject);
// ...
string id = complexObject.UserId;
P.S.: Please note that the object's methods or state is not going to get serialized, only the public properties are.
Can your action just return your object? If so, your client code would look something like (using HttpClient)
var result = client.GetAsync(url).Result;
var myObj = await result.Content.ReadAsAsync<T>();

Can't query/order on built-in rally fields "could not read all instances of class com.f4tech.slm.domain.Artifact"

I'm using v2.0 of the API via the C# dll. But this problem also happens when I pass a Query String to the v2.0 API via https://rally1.rallydev.com/slm/doc/webservice/
I'm querying at the Artifact level because I need both Defects and Stories. I tried to see what kind of query string the Rally front end is using, and it passes custom fields and built-in fields to the artifact query. I am doing the same thing, but am not finding any luck getting it to work.
I need to be able to filter out the released items from my query. Furthermore, I also need to sort by the custom c_ReleaseType field as well as the built-in DragAndDropRank field. I'm guessing this is a problem because those built-in fields are not actually on the Artifact object, but why would the custom fields work? They're not on the Artifact object either. It might just be a problem I'm not able to guess at hidden in the API. If I can query these objects based on custom fields, I would expect the ability would exist to query them by built-in fields as well, even if those fields don't exist on the Ancestor object.
For the sake of the example, I am leaving out a bunch of the setup code... and only leaving in the code that causes the issues.
var request = new Request("Artifact");
request.Order = "DragAndDropRank";
//"Could not read: could not read all instances of class com.f4tech.slm.domain.Artifact"
When I comment the Order by DragAndDropRank line, it works.
var request = new Request("Artifact");
request.Query = (new Query("c_SomeCustomField", Query.Operator.Equals, "somevalue").
And(new Query("Release", Query.Operator.Equals, "null")));
//"Could not read: could not read all instances of class com.f4tech.slm.domain.Artifact"
When I take the Release part out of the query, it works.
var request = new Request("Artifact");
request.Query = (((new Query("TypeDefOid", Query.Operator.Equals, "someID").
And(new Query("c_SomeCustomField", Query.Operator.Equals, "somevalue"))).
And(new Query("DirectChildrenCount", Query.Operator.Equals, "0"))));
//"Could not read: could not read all instances of class com.f4tech.slm.domain.Artifact"
When I take the DirectChildrenCount part out of the query, it works.
Here's an example of the problem demonstrated by an API call.
https://rally1.rallydev.com/slm/webservice/v2.0/artifact?query=(c_KanbanState%20%3D%20%22Backlog%22)&order=DragAndDropRank&start=1&pagesize=20
When I remove the Order by DragAndDropRank querystring, it works.
I think most of your trouble is due to the fact that in order to use the Artifact endpoint you need to specify a types parameter so it knows which artifact sub classes to include.
Simply adding that to your example WSAPI query above causes it to return successfully:
https://rally1.rallydev.com/slm/webservice/v2.0/artifact?query=(c_KanbanState = "Backlog")&order=DragAndDropRank&start=1&pagesize=20&types=hierarchicalrequirement,defect
However I'm not tally sure if the C# API allows you to encode additional custom parameters onto the request...
Your question already contains the answer.
UserStory (HierarchicalRequirement in WS API) and Defect inherit some of their fields from Artifact, e.g. FormattedID, Name, Description, LastUpdateDate, etc. You may use those fields in the context of Artifact type.
The fields that you are trying to access on Artifact object do not exist on it. They exist on a child level, e.g. DragAndDropRank, Release, Iteration. It is not possible to use those fields in the context of Artifact type.
Parent objects don't have access to attributes specific to child object.
Artifact is an abstract type.
If you need to filter by Release, you need to make two separate requests - one for stories, the other for defects.

Can I pass a linked list from a C# Web Service to a JavaScript function?

I've created a linked list class in my JavaScript code and then translated that code into C#.
Right now I have a JavaScript function that calls a Web Service in order to get an array of names, the JavaScript onComplete function then takes that array and makes it into a linked list.
Is there any way I can create the linked list in the Web Service and pass it back to be used by the JavaScript code or can linked lists not transfer properly?
Edit: Let me rephrase my question to something that makes a little more sense. If you have a custom made object created by a class say.... class User, and that class has a variable called user name. If you pass a User object: objUser, back from C# to JavaScript, how does the JavaScript know it can access objUser.userName? What about possible methods it can invoke on this user object?
I had a similar question when I was creating my ASP.NET MVC application. Basically the answer is that JavaScript does not have the same concept of Types as in C#.
Let's say that you've decided to use JSON to pass data between your client and server in your application. The choice of JSON, XML, YAML or other format is not important.
Server Side
On your server side, in your C# code, you can do something like this (assuming you are using a JSON library of some sort):
var myLinkedList = JsonConvert.DeserializeObject<LinkedList>(json);
Now you've got a myLinkedList variable of Type LinkedList. myLinkedList now behaves like all LinkedList instances.
Client Side
However on the client site, in your JavaScript code, you probably do something like this:
function LinkedList(){
//Constructor for your LinkedList
};
LinkedList.prototype = {
//Various functions to operate on your linked list
};
You need to write something like this to deserialize the data that returns from the server:
var linkedList = JSON.parse(jsonString);
Note that there is NO WAY to indicate that you want this deserialized data to go into the LinkedList "class" that you've defined earlier. JavaScript does not understand that LinkedList is a "class" that you've added functionality to using prototype.
What you get back is a JavaScript object.
One way to get around this is to do something like this:
var linkedList = new LinkedList();
var deserializedObject = JSON.parse(jsonString);
linkedList.Items = deserializedObject.Items;
Basically, you'd have to copy over all the state from your deserialized object into your linkedList variable.

Categories

Resources