Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NancyFx binding a model to a dynamic type?

In Nancy, is there a way to bind the content of a POST request to a dynamic type?

For example:.

// sample POST data: { "Name": "TestName", "Value": "TestValue" }

// model class
public class MyClass {
    public string Name { get; set; }
    public string Value { get; set; }
}

// NancyFx POST url
Post["/apiurl"] = p => {

    // this binding works just fine
    var stronglyTypedModel = this.Bind<MyClass>();

    // the following bindings do not work
    // there are no 'Name' or 'Value' properties on the resulting object
    dynamic dynamicModel1 = this.Bind();
    var dynamicModel2 = this.Bind<dynamic>();
    ExpandoObject dynamicModel3 = this.Bind();
    var dynamicModel4 = this.Bind<ExpandoObject>();

}
like image 329
Aaron Drenberg Avatar asked May 23 '13 19:05

Aaron Drenberg


2 Answers

Out of the box Nancy does not support dynamic model binding. TheCodeJunkie has written a quick ModelBinder to achieve that tho.

https://gist.github.com/thecodejunkie/5521941

Then you can use it like so

dynamic model = this.Bind<DynamicDictionary>();

like image 86
Phill Avatar answered Nov 07 '22 08:11

Phill


As the previous answers point, there is no support for binding directly to a dynamic type, the most similar one is the ModelBinder provided by TheCodeJunkie in https://gist.github.com/thecodejunkie/5521941

However, this approach has a problem, and is that the DynamicDictionary resulting from this code does not serialize later properly, producing only the keys of the dictionary and losing the values. This is described here Why does storing a Nancy.DynamicDictionary in RavenDB only save the property-names and not the property-values? and as of today (version 1.4.3) is still happening, limiting seriously this approach.

The solution is to use a simple trick, accessing the raw data received in the POST and deserializing using JSON.Net. In your example it would be:

using System;
using System.Dynamic;
using Nancy;
using Nancy.Extensions;
using Newtonsoft.Json;

Post["/apiurl"] = p => {
    dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(Request.Body.AsString());

    //Now you can access the object using its properties
    return Response.AsJson((object)new { a = obj.Prop1 });
}

Note that you need to use Nancy.Extensions for the Request.Body.AsString() call.

like image 24
maki Avatar answered Nov 07 '22 09:11

maki