.NET Core json serialization of properties on dynamic (ExpandoObject) - asp.net-web-api

I have a web api in .NET Core 1.0 and I like the new feature that properties are by default serialized to camelCasing instead of PascalCasing.
However, some of my api methods are returning dynamic or ExpandoObject and the properties on those are serialized as they are, meaning if I add them to the dynamic object as PascalCasing then that's how they will be serialized.
I figure it's because a dynamic object is closely related to Dictionary<string, object> and that's why it is behaving differently.
How can I make the dynamic be serialized with camelCasing in a nice way?
(I could do it by re-creating the dictionary in every returned dynamic with a lowercase key just before returning them from the API, but I am looking for a quite nice way to accomplish the goal)

This can be solved with this in Startup.cs -> ConfigureServices:
services.AddMvc().AddJsonOptions(opt =>
{
opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
It is mentioned a few places that this is now the default behavior for ASP.NET Core 1.0 but that is actually not true. Adding this line affects dynamic properties and those are not affected by default.

Related

OData V4 (webapi) patch with NavigationProperty collection breaks deserailization on server

I’m trying to go against a Web API Patch method that accepts a Delta. My entity has a navigational property that is a collection. The domain model is trivial, I have a team (entity) and a collection of members (navigational property).
I’m using HttpClient directly instead of the OData client.
The problem I’m running into is that when I send a patch request with the payload = a Team, the Delta deserialized in my controller is null when I include the navigational property collection in my payload.
Eg (ignore that the missing quotes, this is typed in}:
{ Name: Foo } -> serializes to Delta successfully.
{Name: Foo, Members : [] } -> fails to serialize and Delta is null.
Is this supported? I could not find concrete documentation online about whether you can supply navigational properties as an entire collection on patch (not looking for merge support, just want full replace of the collection.)
I also tried tweaking my client to directly send a Delta payload, but the default JsonMediaTypeFormatter is unable to serialize this into a valid request body (always produces empty Json), and the ODataMediaTypeFormatter throws an exception saying it cannot write an object of type Delta, although I have initialized it with every ODataPayloadKind.
I’m sure I’m either doing something wrong or missing something basic, assuming using Delta + patch with HttpClient is not this challenging.
For OData spec, it says:
11.4.3 Update an Entity
...
The entity MUST NOT contain related entities as inline content. It MAY contain binding information for navigation properties. For single-valued navigation properties this replaces the relationship. For collection-valued navigation properties this adds to the relationship.
That is you can't put the navigation properties in the Patch request content.
From Web API OData, it has these codes and these codes. It means that it doesn't allow to patch navigation property form entity.
However, you can shoot your target by following steps:
Patch the principal entity (team)
Patch the dependent entities (members)
use the $ref to update the link
You can refer to my simple test project.

grails - I need to define my validation at runtime

I have an idea to read an XML document from the database and generate simple CRUD screens (via Grails) based on the data defined. My application will call RESTFul services to persist the data so I don't need Hibernate on the client side. I have ideas about how to generate the UI but where I'm stumped is in how to perform the validation.
I'll have a single, generic domain/command object that contains only the fields that are common for all instances of this "runtime" data type. All other fields are defined via the XML found in the database. I need something like this:
String xml // defines the fields, constraints, UI information for this data type
def constraints = {
callMyCustomValidator(obj)
}
and in my callMyCustomValidator method, I'll extract the xml for obj and perform my validation as needed.
Note: We have a working example of this in a different app (written in java/servlers/jsp) and without any formal "framework" this isn't difficult to do. Why do I need this? We need to add simple datatypes on the fly (via script) without a release.
You can use the validator to add custom validation to your domain class. Just add this to some of your common fields.

Model Binder of Json.Net not being used when i post an object

To clarify...
I configure my WebApiConfig like so:
config.Formatters.JsonFormatter.SerializerSettings.Binder = new TypeNameSerializationBinder("namespace.{0}, assembly");
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
This should allow me to bind derived classes to base class.
And binder does work when WebApi serializes objects to JSON, and sends them to client, but when I post them back to server, the binder isn't used (BindToType method never gets called), and my objects get bound to base class.
When i serialize/deserialize objects manually with this settings it all works fine.
Any ideas?
I had the same problem when trying to deserialize complex objects with a custom JsonConverters. I needed this because I'm using DbGeometry for storing users locations.
I broke my head on this a couple of days, I really thought I was doing something wrong, because every time I posted an geometry to the Web API, the complex type parameter was set to null. This while JsonConverter was perfectly able to convert the json to an filled object.
My workaround for this is written below. I don't like that I can't just use the parameter as I'm supposed to do. But it works, at last.
[HttpPost]
public MyComplexType SaveMyComplexType()
{
var json = Request.Content.ReadAsStringAsync().Result;
var myComplexType = JsonConvert.DeserializeObject<MyComplexType>(json);
//todo: validation and save to db
return myComplexType;
}
After some research, I found that this is a bug in ASP.NET Web Api. When the url encoded parameters are parsed, it just creates a new JsonSerializer (without passing global settings).
I filed it here
http://aspnetwebstack.codeplex.com/workitem/609

Problems deserializing Dictionarys in MVC 3 for AJAX request (an approach that works out of the box with classic ASP.NET Webforms)

I've been successfully WebForms for AJAX calls with relatively complex set of parameters (called using jQuery.ajax). We're attempting to try using the same approach in MVC 3 but seem to be falling at the first hurdle with MVC failing to deserialize Dictionary arrays successfully.
The approach that works without issue in ASP.NET WebForms "classic" is below:
[WebMethod]
public static JQGrid.JQGridData GetListForJQGrid(int? iPageSize, int? iPage, int? iMaxRecords, string sSortField, string sSortOrder,
Dictionary<string, string> dSearchOptions, Dictionary<string, object>[] aOriginalColumnDefinition, string[] aExtraDataColumns)
And below is the MVC 3 equivalent: (nb exactly the same name/parameters - different return type but I don't think that is relevant)
[HttpPost]
public JSONResult GetListForJQGrid(int? iPageSize, int? iPage, int? iMaxRecords, string sSortField, string sSortOrder,
Dictionary<string, string> dSearchOptions, Dictionary<string, object>[] aOriginalColumnDefinition, string[] aExtraDataColumns)
With the WebMethod all the data deserializes perfectly. However, when the MVC method is called all the simple parameters deserialize fine but for some unknown reason the array of Dictionary's arrives as an array of nulls.
So, off the back of that a number of questions:
Has anyone else experienced problems with MVC 3 deserialization of arrays of dictionaries?
Does MVC 3 by default not use System.Web.Script.Serialization.JavaScriptSerializer which is I think what ASP.NET WebMethods use under the bonnet?
Can I force MVC 3 to use System.Web.Script.Serialization.JavaScriptSerializer instead of what it is using?
Or am I missing something / should my approach be slightly different? Please note that at least for now we'll need to share the client side code between classic ASP.NET WebMethods and MVC 3 and so we want that to remain as is if possible.
Finally, I can see there is a possible workaround that could be used looking at this question: POST json dictionary . Is this workaround the only game in town or have things improved since this question was posed?
jQuery AJAX call:
$.ajax(_oJQGProperties.sURL, //URL of WebService/PageMethod used
{
data: JSON.stringify(oPostData),
type: "POST",
contentType: "application/json",
complete: DataCallback
});
Example JSON.stringify(oPostData):
{
"dSearchOptions":{},
"aOriginalColumnDefinition":
[
{"name":"ID","sortable":false,"hidedlg":true,"align":"right","title":false,"width":40},
{"name":"URL","sortable":false,"hidedlg":true,"align":"left","title":false,"width":250,"link":"javascript:DoSummat(this,'{0}');","textfield":"Name"},
{"name":"Description","sortable":false,"hidedlg":true,"align":"left","title":false,"width":620}
],
"aExtraDataColumns":["Name"],
"_search":false,
"iPageSize":-1,
"iPage":1,
"sSortField":"",
"sSortOrder":"",
"iMaxRecords":0
}
I don't have any experience with binding to a dictionary array, but one possible solution is to use a custom model binder. Scott Hanselman has a blog post on this subject that you might find useful: Splitting DateTime - Unit Testing ASP.NET MVC Custom Model.
Long time getting to update this but I thought I'd share where we got to. The problem turned out to be a bug - details of which can be found here:
Bug:
http://connect.microsoft.com/VisualStudio/feedback/details/636647/make-jsonvalueproviderfactory-work-with-dictionary-types-in-asp-net-mvc
Workaround:
POST json dictionary
We used the stated workaround which has been fine. I'm not too clear as to when the fix will be shipped and where exactly the bug lay. (Is it .NET dependant / MVC dependant etc) If anyone else knows I'd love to find out :-)
Update
I haven't heard still if this is shipped (I assume it goes out with MVC 4?) but in the interim this may be an alternative solution:
http://www.dalsoft.co.uk/blog/index.php/2012/01/10/asp-net-mvc-3-improved-jsonvalueproviderfactory-using-json-net/
Update 2
This has now been shipped as a fix with MVC 4. The issue remains unresolved in MVC 3 and so I've now written it up as a blog post here:
http://icanmakethiswork.blogspot.com/2012/10/mvc-3-meet-dictionary.html
I ran into this issue too. After finding this SO post, I thought about upgrading to MVC4, but it's too risky to do all at once in my environment so scratch that.
This link posted in Johnny Reilly's answer looked promising, but it required flattening my dictionary to a string. Because my MVC model is bidirectional (it's used for reads and writes), and I really wanted that dictionary structure I decided to pass on that too. It would have been a real pain to keep two properties for one value. I would have needed to add more tests, watch out for edge cases, etc.
Johnny's JsonValueProviderFactory link seemed promising too, but a bit arcane. I'm also not entirely comfortable monkeying around with a part of MVC like that. I had only a few hours to figure this problem out so I passed on this too.
Then I found this link somewhere, and thought "Yes! this is more like what I want!". In other words attack the model binding problem by using a custom binder. Replace the buggy one with something else, and use MVC's built-in capability to do so. Unfortunately, this did not work as my use case was List of T, and T was my model. This totally did not work with the sample. So I hacked away at it and ultimately failed.
Then, I got a lightbulb moment - JSON.NET does not have this problem. I use it all the time for doing all sorts of things, from cloning objects, to logging, to REST service endpoints. Why not model binding? So I ultimately ended up with this and my problem was solved. I think it should work with just about anything - I trust JSON.NET =)
/// <summary>
/// Custom binder that maps JSON data in the request body to a model class using JSON.NET.
/// </summary>
/// <typeparam name="T">Model type being bound</typeparam>
/// <remarks>
/// This binder is very useful when your MVC3 model contains dictionaries, something that it can't map (this is a known bug, fixed with MVC 4)
/// </remarks>
public class CustomJsonModelBinder<T> : DefaultModelBinder
where T : class
{
/// <summary>
/// Binds the model by using the specified controller context and binding context.
/// </summary>
/// <returns>
/// The bound object.
/// </returns>
/// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><exception cref="T:System.ArgumentNullException">The <paramref name="bindingContext "/>parameter is null.</exception>
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
HttpRequestBase request = controllerContext.HttpContext.Request;
request.InputStream.Position = 0;
var input = new StreamReader(request.InputStream).ReadToEnd();
T modelObject = JsonConvert.DeserializeObject<T>(input);
return modelObject;
}
}
To apply the binder, I added an attribute to my model parameter. This causes MVC3 to use my binder instead of the default. Something like this:
public ActionResult SomeAction(
[ModelBinder(typeof(CustomJsonModelBinder<List<MyModel>>))] // This custom binder works around a known dictionary binding bug in MVC3
List<MyModel> myModelList, int someId)
{
One caveat - I was using POST with content type "application/json". If you're doing something like form or multipart data instead it will probably crash horribly.

Is there a way to Iterate all Controllers/Actions in an ASP.NET MVC3 Site?

I'm trying to make a dynamic menu function in an ASP.NET MVC 3 website - and I'd like to know if there is a built-in way to get all of the Controllers and Actions at runtime?
I realize that I can use reflection to find all public methods on my controllers, but this doesn't exactly give me the relative URL that I should put in the <a href="..."> tag.
Also, I'm going to be decorating some of the 'actions' with filter attributes that dictate whether the current user can see/goto those pages. So it would be best if I had access to the filters as well so as to be able to call the IsAccessGranted() method.
What are my options? What is the best option?
I actually just did that two weeks ago.
var q = from type in Assembly.GetExecutingAssembly().GetTypes()
where type.IsClass && type.Namespace != null && type.Namespace.Contains("Controller")
select type;
q.ToList().ForEach(type => doWhatYouNeedToDo(type)));
if you are using T4MVC, then this script will return double entries. To avoid this, work with
&& !type.Name.Contains("T4MVC")
In the method doWhatYouNeedToDo() you could transform the Type object into a DTO that suits your needs and add work further with it.
As far as your dynamic menu is concerned, you could use the MvcSiteMapProvider and implement your own dynamic sitemapprovider with it, so you are no longer bound to the static sitemap xml file.
But reflection is quite slow in .NET, so you might want to store representations of your controllers and method in the database.
There is no built in mechanism in MVC to enumerate over all of your controllers and actions. You would have to use reflection to inspect all the loaded types and look at their methods and the associated attributes. Of course this is assuming that you are using the default reflection-based action dispatching mechanism. Since MVC's pipeline can be replaced in a number of places its easy to inject a system for invoking action methods that is not based on CLR classes and methods. But if you have complete control over your application than you life is easier.
Try TVMVC. You'll still have to use reflection, but the t4 templates will generate a class that's easier to iterate over.

Resources