Why does storing a Nancy.DynamicDictionary in RavenDB only save the property-names and not the property-values?
Asked Answered
M

1

3

I am trying to save (RavenDB build 960) the names and values of form data items passed into a Nancy Module via its built in Request.Form.

If I save a straightforward instance of a dynamic object (with test properties and values) then everything works and both the property names and values are saved. However, if I use Nancy's Request.Form then only the dynamic property names are saved.

I understand that I will have to deal with further issues to do with restoring the correct types when retrieving the dynamic data (RavenJObjects etc) but for now, I want to solve the problem of saving the dynamic names / values in the first place.

Here is the entire test request and code:

Fiddler Request (PUT) enter image description here

Nancy Module

Put["/report/{name}/add"] = parameters =>
    {
        reportService.AddTestDynamic(Db, parameters.name, Request.Form);
        return HttpStatusCode.Created;
    };

Service

public void AddTestDynamic(IDocumentSession db, string name, dynamic data)
{
    var testDynamic = new TestDynamic
    {
            Name = name,
            Data = data
    };
    db.Store(testDynamic);
    db.SaveChanges();
}

TestDynamic Class

public class TestDynamic
{
    public string Name;
    public dynamic Data;
}

Dynamic contents of Request.Form at runtime enter image description here

Resulting RavenDB Document

{
  "Name": "test",
  "Data": [
    "username",
    "age"
  ]
}

Note: The type of the Request.Form is Nancy.DynamicDictionary. I think this may be the problem since it inherits from IEnumerable<string> and not the expected IEnumerable<string, object>. I think that RavenDB is enumerating the DynamicDictionary and only getting back the dynamic member-names rather than the member name / value pairs.

Can anybody tell me how or whether I can treat the Request.Form as a dynamic object with respect to saving it to RavenDB? If possible I want to avoid any hand-crafted enumeration of DynamicDictionary to build a dynamic instance so that RavenDB can serialise correctly.

Thank You

Edit 1 @Ayende

The DynamicDictionary appears to implement the GetDynamicMemberNames() method:

Nancy.DynamicDictionary

Taking a look at the code on GitHub reveals the following implementation:

public override IEnumerable<string> GetDynamicMemberNames()
{
    return dictionary.Keys;
}

Is this what you would expect to see here?

Edit 2 @TheCodeJunkie

Thanks for the code update. To test this I have:

  1. Created a local clone of the NancyFx/Nancy master branch from GitHub
  2. Added the Nancy.csproj to my solution and referenced the project
  3. Run the same test as above

RavenDB Document from new DynamicDictionary

{
  "Name": "test",
  "Data": {
    "$type": "Nancy.DynamicDictionary, Nancy",
    "username": {},
    "age": {}
  }
}

You can see that the resulting document is an improvement. The DynamicDictionary type information is now being correctly picked up by RavenDB and whilst the dynamic property-names are correctly serialized, unfortunately the dynamic property-values are not.

The image below shows the new look DynamicDictionary in action. It all looks fine to me, the new Dictionary interface is clearly visible. The only thing I noticed was that the dynamic 'Results view' (as opposed to the 'Dynamic view') in the debugger, shows just the property-names and not their values. The 'Dynamic view' shows both as before (see image above).

Contents of DynamicDictionary at run time enter image description here

Milburt answered 24/6, 2012 at 15:33 Comment(0)
P
1

biofractal, The problem is the DynamicDictionary, in JSON, types can be either objects or lists ,they can't be both. And for dynamic object serialization, we rely on the implementation of GetDynamicMemberNames() to get the properties, and I assume that is isn't there.

Pensionary answered 25/6, 2012 at 7:34 Comment(4)
GetDynamicMemberNames() is indeed there github.com/NancyFx/Nancy/blob/master/src/Nancy/… I've just added IDictionary to DynamicDictionary and it will be pushed to master, and made part of the 0.12 release, todayWadmal
@TheCodeJunkie. Please see Edit 2 above. Sorry, I am confused. Was the fix you described intended to allow property values to be serialized by RavenDB? Or should I be transferring the Form data items into a standard dictionary before serializing? Thanks.Milburt
You could try by building from source (read our how to build file in the repo and getting local nugets) and see if that resolved it. Your questions sparked the implementation of IDictionary, it's been something we've talked about before but never got around to doingWadmal
@TheCodeJunkie. That's great. Thanks again for the code update. I will try to run off the source with local nugets. I found (see edit 2 above) that creating a simple reference to the latest Nancy source project does not fix my problem, that is dynamic values are not serialised to RavenDB, perhaps I need the local nugets as you suggest? FWIW, Did you create a unit-test to see if the new DynamicDictionary allows for dynamic key / value serialisation?Milburt

© 2022 - 2024 — McMap. All rights reserved.