dsuryd / dotNetify

Simple, lightweight, yet powerful way to build real-time web apps.
https://dotnetify.net
Other
1.17k stars 164 forks source link

Camel casing VM properties names #176

Closed antonyrey closed 5 years ago

antonyrey commented 5 years ago

Hello,

First thank you for this amazing library !

I have a small question : I've been able to camel-case properties names inside my VM properties using app.UseDotNetify(config => config.UseJsonSerializerSettings....)

However, is it possible to pascal-case top level VM properties as well ?

For example :

public class Person {

 public string Name { get; set; }

}

public class MyVM : BaseVM {

    public Person Person
    {
        get { return Get<Person>(); }
        set { Set(value); }
    }

}


=> "Name" gets serialized to "name" which is OK => "Person" gets serialized to "Person" which is not what i want

Thanks a lot, have a nice day !

dsuryd commented 5 years ago

This is the settings that I used:

private class CamelCaseContractResolver : VMContractResolver
{
   public CamelCaseContractResolver() : base()
   {
       NamingStrategy = new CamelCaseNamingStrategy();
   }
}
...
appBuilder.UseDotNetify(config => config.UseJsonSerializerSettings(new JsonSerializerSettings
{
  ContractResolver = new CamelCaseContractResolver()
}))

Both Name and Person are camel-cased: image

TheTrigger commented 5 years ago

Using CamelCaseNamingStrategy i have to apply this strategy on my backend. Mixing domains is not good, use of literal strings is bad and verbose.

Example: this.RemoveList("allMarkers", id); instead of this.RemoveList(nameof(AllMarkers), id);

And public string AllMarkers_itemKey => "id"; instead of public string AllMarkers_itemKey => nameof(Marker.Id);

There a way to make it case-insensitive?

Thank you

dsuryd commented 5 years ago

Both Javascript and C# are case-sensitive, so if you want to maintain two different casing conventions, you'll have to write your own conversion. There are several ways to do it, from simple things like nameof(var).ToCamelCase() (ToCamelCase being your own extension method), custom JSON serializer, middleware, or overriding setState on the client-side.

TheTrigger commented 5 years ago

Here my piece of code: image

Obv I want to remove the literal string, and as you said a middleware would be great. But not sure how to do... Could you help, please? Thanks

dsuryd commented 5 years ago

Didn't say it's great, just one of the implementation alternatives :) Choose middleware if you need better control on doing specific post-processing on the data you're about to send that has nothing to do with business logic, such as selectively changing the casing.

Here's an example of a middleware. You can write similar one that checks if the context.CallType is Response_VM, and proceed to transform the response data.

TheTrigger commented 5 years ago
using DotNetify;
using System.Threading.Tasks;

namespace DemoDotNetify.Middlewares
{
    public class ConventionCaseMiddleware : DotNetify.IMiddleware
    {
        public ConventionCaseMiddleware()
        {
        }

        public Task Invoke(DotNetifyHubContext context, NextDelegate next)
        {
            if (context.CallType == "Response_VM")
            {
                // context.Data json string
            }

            return next(context);
        }
    }
}

Ok I did that, but I don't get how to solve the problem. Should I Json.Deserialize and then Serialize using the right case (replacing Data content)? Or inject in some way a new JsonSerializeOptions?

dsuryd commented 5 years ago

Yes, replacing Data content. You probably can just do regex string replace.

TheTrigger commented 5 years ago

Unfortunately, it's not working for CRUD. When I connect with the Vue client I receive the markers, but getting an error when trying to remove:

[SharedMarkers] 'AllMarkers' is not found or not an array.
app.UseDotNetify(config =>
{
    config.UseMiddleware<ConventionCaseMiddleware>();
using System.Text.RegularExpressions;
using DotNetify;
using System.Threading.Tasks;

namespace DemoDotNetify.Middlewares
{
    public class ConventionCaseMiddleware : DotNetify.IMiddleware
    {
        public ConventionCaseMiddleware()
        {
        }

        public Task Invoke(DotNetifyHubContext context, NextDelegate next)
        {
            if (context.CallType == "Response_VM" && context.Data is string json)
            {
                var regex = new Regex(@"(\w*)_(add|update|remove|itemKey)");  
                context.Data = regex.Replace(json, Capitalize);
            }

            return next(context);
        }

        private static string Capitalize(Match match)
        {
            var c = match.Value.ToCharArray();
            c[0] = char.ToUpper(c[0]);
            return new string(c);
        }
    }
}

I've already tried to serialize and deserialize the object, but it was worse.

I'm wrong if I say that would be easy to just make comparison case-insensitive? Somewhere here What is the reason to keep it case-sensitive? While JsonSerialier isn't, and no one would / should name properties that way. (asp.net core deserialization process, automatically translate upper, lower, snake cases etc)

Thank you

dsuryd commented 5 years ago

Are you not trying to convert your property name to camel case? If so, the line below should be ToLower:

  private static string Capitalize(Match match)
  {
      var c = match.Value.ToCharArray();
       c[0] = char.ToUpper(c[0]);    // <-- .ToLower()
       return new string(c);
   }

I've tested it with my CRUD sample, it works great.

TheTrigger commented 5 years ago

I would use camel-case (or better snake-case) from javascript, and pascal-case from C# code. Data comes from js as camelCase or snake_case, then C#/dotnetify should be able to get the right property (usually PascalCase). Keep in mind aspnetcore has this implicit process during deserialization. This lack could give problems when working with multiple systems. It seems strange to me that no one has thought of it. In short, use the naming conventions of each language, maybe I'm autistic lol, but the that give various benefits

dsuryd commented 5 years ago

I understand the desire, and I believe it has been thoroughly accommodated by the provision of both custom JSON serializer and middleware. Unless there are use cases that cannot be satisfactorily covered by these, I don't see any need to change the behavior of the core framework in this regard.

Paulskit commented 3 years ago

Hey @dsuryd, thank you for the library. I've come across this issue and I think it still valid. I implemented a CamelCaseContractResolver as per your suggestion and it works fine on the first render. However, when there is an update, things go wrong again. image

Please advise. Thank you.

dsuryd commented 3 years ago

This could be a bug. Could you create a new issue for this? Thanks.

Paulskit commented 3 years ago

Here you go #295