【问题标题】:How to serialize a function to json (using razor @<text>)如何将函数序列化为 json(使用 razor @<text>)
【发布时间】:2013-05-20 08:06:44
【问题描述】:

如何将客户端函数序列化为 json 对象? (类似于剑道控制的工作原理)

这就是我目前所拥有的......

查看:

@Html.TestControl(@<text>function(){ alert("test"); }</text>)

控制助手:

public static HtmlString TestControl<TModel>(this HtmlHelper<TModel> helper, Func<object, object> onSubmit)

{
    var obj = new {onSubmit = onSubmit.Invoke(null) };
    var jsonObj = new JavaScriptSerializer().Serialize(obj);
    return new HtmlString(string.Format("<script>var obj = {0};</script>", jsonObj));
}

输出:

<script>var obj = {"onSubmit":{}};</script>

期望的输出:

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

我可以看到帮助器中obj.onSubmit的值是函数...但是如何让函数序列化并出现在json对象中(作为函数)?

更新:

最好使用@ 来定义匿名函数内联。我们使用具有这种语法的 Kendo 控件,目标是保持代码一致。

以下是剑道控件语法的示例: http://docs.kendoui.com/api/wrappers/aspnet-mvc/Kendo.Mvc.UI.Fluent/UploadEventBuilder

【问题讨论】:

    标签: asp.net-mvc json razor


    【解决方案1】:

    我花了更多时间搜索并找到了类似的帖子,但没有找到解决方案:

    Serializing a function as a parameter in json using C#

    JSON serializing an object with function parameter

    终于使用 Json.net 库让它工作了。使用 JRaw 类将生成一个带有定义为函数的 onSubmit 属性的 json 对象。

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

    更新控制助手:

    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));
    }
    

    输出:

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

    现在我可以在客户端调用 obj.onSubmit() 来调用函数了。

    【讨论】:

      【解决方案2】:

      根据@ryan 的回答,我稍微升级了一点,更像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());
          }
      

      这里是 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);
          }
      }
      

      你可以像 KendoUI 那样做

      var textBox = new TextBox
      {
          OnChange = @<text>
                          function(e){
      
                                  return e;
                          }
                      </text>
      };
      

      【讨论】:

        【解决方案3】:

        只需将此 onSubmit 参数设为字符串并按原样使用其值。调用助手时不再需要文本标签。

        【讨论】:

        • 在客户端,我想调用函数(例如:obj.onSubmit())...如果值是字符串,我不能将 onSubmit 作为函数调用跨度>
        • 我认为 yoy 将服务器上的功能与客户端上的功能混淆了。将参数设为syring,不要在服务端序列化,直接输出到客户端,方便调用。
        • 我认为我不会混淆这两者。 @ 块中定义的函数是一个 javascript 函数。控制助手(服务器端)只是构建创建 json 对象所需的 js 代码,我以后可以将其演变为定义 jquery 方法的选项。
        【解决方案4】:

        您将服务器上的功能与客户端上的功能混淆了。您实际上是在服务器上执行 onSubmit ,结果被放入您的对象中,您将其序列化为 json。

        改为:

        将 TestControl 的第二个参数设为字符串。另外,不要序列化对象。相反,请手动创建您的 json。

        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));
        }
        

        那么你可以使用:

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

        您的 jsonObj 将是:

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

        最后,您的 TestControl() 方法将返回

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

        【讨论】:

        • 我们使用带有@ 语法的Kendo 控件。我想使用 @ 来保持剑道控件和自定义控件之间的语法一致。你能提供一个使用@ 的例子吗?从剑道签名中我可以看出,这是通过将参数设为 Func. 来实现的
        猜你喜欢
        • 2017-09-14
        • 1970-01-01
        • 2012-06-22
        • 1970-01-01
        • 1970-01-01
        • 2017-07-30
        • 2014-10-08
        • 2013-07-11
        • 1970-01-01
        相关资源
        最近更新 更多