How to serialize a function to json (using razor @)

前端 未结 4 1466
被撕碎了的回忆
被撕碎了的回忆 2021-01-14 14:07

How can I serialize a client function to a json object? (similar to how kendo controls work)

This is what I have so far...

View:

@Html.TestCo         


        
相关标签:
4条回答
  • 2021-01-14 14:20

    You are confusing a function on the server with a function on the client. You're actually executing onSubmit on the server and the result of that is being put into your object which you serialize into json.

    Instead:

    Make your 2nd parameter to TestControl a string. Also, don't serialize an object. Instead, create your json manually.

    public static HtmlString TestControl<TModel>(this HtmlHelper<TModel> helper, string onSubmit)
    {
      string jsonObj = String.Format("{{ \"onSubmit\": {0} }}", onSubmit);
      return new HtmlString(string.Format("<script>var obj = {0};</script>", jsonObj));
    }
    

    Then you can use:

    @Html.TestControl("function(){ alert('test'); }")
    

    Your jsonObj will be:

    { "onSubmit": function(){ alert('test'); } }
    

    and finally, your TestControl() method will return

    <script>var obj = { "onSubmit": function(){ alert("test"); } };</script>
    
    0 讨论(0)
  • 2021-01-14 14:21

    Based on @ryan's answer, I upgrade a little bit to more like kendoUI.

    public class TextBox : BaseControl
    {
        [JsonProperty("onChange", NullValueHandling = NullValueHandling.Ignore)]
        [JsonConverter(typeof(JsFunctionConverter))]
        public Func<object, object> OnChange { get; set; }
    
        public override MvcHtmlString Render()
        {
            // Create html
            // <input />
            _tagBuilder = new TagBuilder("input");
    
            // Add script
            StringBuilder builder = new StringBuilder(base.Render().ToString());
            string script = @"<script>var {0} = {{name: '{0}', scope : angular.element($('#{0}')).scope(), options: {1}}}; textBox({0});</script>";
    
            BuildOptions();
            builder.AppendFormat(script, Name, JsonConvert.SerializeObject(this));
            return MvcHtmlString.Create(builder.ToString());
        }
    

    Here is JsFunctionConverter:

    public class JsFunctionConverter : JsonConverter
    {
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
        }
    
        public override bool CanRead
        {
            get { return false; }
        }
    
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof (string) || objectType == typeof (Func<object,object>);
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            JRaw jRawData;
    
            if (value.GetType() == typeof(Func<object, object>))
            {
                jRawData = new JRaw(((Func<object,object>)value).Invoke(null));
            }
            else
            {
                jRawData = new JRaw(value);
            }
    
            jRawData.WriteTo(writer);
        }
    }
    

    And you can do it like KendoUI

    var textBox = new TextBox
    {
        OnChange = @<text>
                        function(e){
    
                                return e;
                        }
                    </text>
    };
    
    0 讨论(0)
  • 2021-01-14 14:28

    Just make this onSubmit argument being a string and use its value as is. You will no longer need the text tags when calling the helper.

    0 讨论(0)
  • 2021-01-14 14:31

    I spent more time searching around and found similar posts but didn't see a solution:

    Serializing a function as a parameter in json using C#

    JSON serializing an object with function parameter

    Finally got it to work using the Json.net library. Using the JRaw class will generate a json object with the onSubmit property defined as a function.

    Json.net documentation: http://james.newtonking.com/projects/json/help/html/SerializeRawJson.htm

    Updated Control Helper:

    public static HtmlString TestControl<TModel>(this HtmlHelper<TModel> helper, Func<object, object> onSubmit)
    {
        var obj = new { onSubmit = new JRaw(onSubmit.Invoke(null).ToString()) };
        var jsonObj = JsonConvert.SerializeObject(obj);
        return new HtmlString(string.Format("<script>var obj = {0};</script>", jsonObj));
    }
    

    Output:

    <script>var obj = {"onSubmit":function(){alert("test");}};</script>
    

    Now I can call obj.onSubmit() on the client to call the function.

    0 讨论(0)
提交回复
热议问题