Why does storing a Nancy.DynamicDictionary in RavenDB only save the property-names and not the property-values?
-
16-06-2021 - |
Pergunta
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)
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
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:
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:
- Created a local clone of the NancyFx/Nancy master branch from GitHub
- Added the Nancy.csproj to my solution and referenced the project
- 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
Solução
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.