We're using
MessagePackSerializer.NonGeneric.Deserialize(type, new ArraySegment<byte>(input, offset, input.Length - offset));
And when we get a payload with value:3 and try to deserialize into public class ValueHolder { public int Value; } we just get the default ValueHolder back with Value == 3
I can implement camelCase msgpack string map key to PascalCase C# member name matcher.
Its name will be ContractlessStandardResolverCamelCase.
By the way, I have a question.
Is case-insensitive a must feature? https://github.com/aspnet/SignalR/issues/1690
MessagePack-CSharp does not use dictionary to match member name, using custom generated automata code.
https://github.com/neuecc/MessagePack-CSharp#deserialize-performance-per-options
so cannot implement case-insensitive code.
We can choose
Currently I'll choose "originalName or camelCase".
But if it can not fill your requirement, please tell me.
I think having a separate resolver for camelCase names is OK.
The requirement is just that we can have a mode where this C# type:
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
can be serialized to and from a MessagePack map similar to this JSON:
{
"firstName": "John",
"lastName": "Doe"
}
then I think we're good. We'd set that resolver as the default in our configuration (to match our JSON default) and then would expose the options for users to change as they please.
The third option (case-insensitive) would better match how JSON.NET handles deserialization though, since it uses a best-match logic where it tries a case-sensitive match and if that fails, falls back to case-insensitive.
Hey, is there an update here? We're looking to try and get this resolved before we ship SignalR using this library because we want similar behavior to JSON.NET. We're definitely OK with this being an optional behavior that we have to enable.
Our desired behavior is a case-insensitive match against property names (which aligns with JSON.NET). We're OK with it being slower, we're also OK if you have it try a few known casings (PascalCase, camelCase, etc.) via a faster automata and then fall back to a Dictionary lookup only when necessary.
about the implementation difficulty,
case-insensitive and fall back is too difficult
because I can not tolerate large performance degradation so I need to create specialized il emit code.
"originalName or camelCase" is easy, only to do replace emit name of intermediate meta type.
at first, I'll try to implement "originalName or camelCase", and case-insensitve is after...
Ok, let's start with that.
What's the current status of the camelCase conversion? I'm using MessagePack-CSharp in a network protocol library that prefers camelCase on the network side, but .NET prefers PascalCase on the code side. There is a bit of a mismatch and this case conversion could fix that.
I don't understand everything from the previous comments. But if the question was whether or not ignoring case would be requested, well I don't need that. For me, "camelCase" is something else than "camelCASE". I guess only the first letter would need to be converted but I'm not sure about all the camelCase edge cases right now.
Anyway, this conversion would be much appreciated. Keep up the good work! (I already made my own JavaScript MessagePack library but JavaScript is much simpler than .NET static typing, and it doesn't need case conversion because camelCase is default in JavaScript already.)
You should be able to use [DataMember(Name="camelCasedName")] on members so that your properties can be PascalCased while the protocol serializes camelCase.
Given our backlog size, and that there's a workaround, I'm closing this as Won't Fix.
If for some reason this workaround doesn't work for you, feel free to comment and we can reconsider.
Would be really great to have a camelCase resolver.
We are currently having .NET clients consuming our API via PascalCased properties which is fine. We are now in the process of adding javascript clients. We would really like to keep the javascript coding conventions of using camelCased properties and at the same time don't force our .NET consumers to update their applications.
So DataMember attribute does not work for us as we'd need different resolvers. The only solution we see is to duplicate all our DTOs and re-map them.
@coonmoo I don't understand how you could get away with this:
We would really like to keep the javascript coding conventions of using camelCased properties and at the same time don't force our .NET consumers to update their applications.
If you change the wire protocol to use camelCase, you break your existing .NET applications. It sounds like you already have .NET applications that you don't want to upset. So the only way to not upset them is to give your javascript clients the ability to read PascalCase properties. And if you want to expose camelCase to them, the javascript library you use would have to do the translation.
If we were to offer camelCase as an option, it would still require an update in a .NET application to use it. So whether you use the attributes to do it now, or an option to automatically do it later, you still have to update the application. And in so doing, you break wire/file compatibility with your earlier version.
To switch to camel case but be able to read pascal case as well, you'd need a custom formatter -- or a dynamic resolver that not only offers camel case as an option but is willing to read either case, which is beyond the original scope of this issue I think.
@AArnott thanks for the explanation, maybe I can clarify our requirement
The .NET client libraries consuming our API are sending a header which we can use to distinct them from JS clients.
The plan was to use the (standard) PascalCase MessagePack resolver only if the header is present. And switch to a pascalCase resolver for all new clients (not sending any header).
We would like to solve that without having our new clients using PascalCase to camelCase mapping
I think it's still very similiar to the original issue. We'd need a way to resolve PascalCase properties using a camelCase wire format without using DataMember/Key annotations
I want to +1 the request for a ContractlessStandardResolverCamelCase.
Both my backend and frontend currently use JSON to communicate. Newtonsoft.Json has the CamelCaseNamingStrategy, meaning all my JS can expect responses from server to be camelCased.
I am now adding MessagePack and I am having trouble with the casing. I do not want to change my JS code and neither do I want to manually add Attributes to decorate my DTO properties with camel cased names. Hence my need for a contractless, camelCase resolver 馃榿
I've had a look through the source code, and as far as I can see it would be rather difficult for me to add this as purely a new custom resolver or even formatter. If I understand correctly it is the DynamicContractlessObjectResolver that allows for contractlessness and looking at the DynamicObjectTypeBuilder.BuildType it is the ObjectSerializationInfo.CreateOrNull that would require updating. This is too deep to be done easily and without lots of code copying from the current implementation. I feel that it should be done with an extra argument similar to forceStringKey/contractless.
Could anyone advise best way to do this?
The built-in resolvers/formatters themselves must be immutable, so we're not talking about an option on the formatters here. Adding a boolean property on the top-level MessagePackSerializationOptions class is an option, but not one I care for much because it only applies to specific formatters that honor it, and it leaves open the question of how to handle properties that are explicitly attributed with a name.
So if I were to design a fix for this, I would combine it with another ask I've heard a few times which is in my mind a new form of a new issue I just filed to describe it: #1060.
Most helpful comment
I think having a separate resolver for
camelCasenames is OK.The requirement is just that we can have a mode where this C# type:
can be serialized to and from a MessagePack map similar to this JSON:
then I think we're good. We'd set that resolver as the default in our configuration (to match our JSON default) and then would expose the options for users to change as they please.
The third option (case-insensitive) would better match how JSON.NET handles deserialization though, since it uses a best-match logic where it tries a case-sensitive match and if that fails, falls back to case-insensitive.