使用MVC4中的JsonConvert.SerializeObject清理输入?

时间:2013-11-02 22:56:51

标签: asp.net-mvc asp.net-mvc-4 knockout.js json.net

长话短说,我试图让JsonConvert.SerializeObject的输出被清理,而不必修改已保存数据的内容。

我正在开发一个在视图中包含以下标记的应用程序:

                 <textarea data-bind="value: aboutMe"></textarea>

如果我保存以下文字,我会遇到问题:

                 <script type="text/javascript">alert("hey")</script>

我在FF中遇到的错误:

enter image description here

违规渲染文字的相关部分:

  

(文档)$。就绪(ko.applyBindings(新   MyProfileVm({“profileUsername”:“admin”,“username”:“Admin”,“aboutMe”:“alert(\”hey \“)”,“title”:“这是一个   简短的自我生物!   :) “ ”缩略图“: ”https://i.imgur.com/H1HYxU9.jpg“, ”locationZip“: ”22182“, ”LOCATIONNAME“:” 维也纳,   VA“

最后 - 在我的观点的底部:

<script type="text/javascript">
    $(document).ready(ko.applyBindings(new MyProfileVm(@Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() })))));
</script>

在这里,我将我从MVC控制器获得的模型传递给j​​s ViewModel,用于挖空以映射到可观察数据。 Raw编码似乎是个问题,但我不确定如何处理它。

要清楚,我从服务器获取数据,然后将其输出到客户端,这会破坏JSON / KO组合。

2 个答案:

答案 0 :(得分:4)

问题是您不能在JavaScript字符串文字中包含结束</script>标记,因为浏览器会将其解释为脚本块的结尾。另见:Script tag in JavaScript string

Asp.Net中没有内置函数可以在输出生成的脚本之前在服务器端处理它,您需要将</script>替换为其他内容:

<script type="text/javascript">
    $(document).ready(ko.applyBindings(new MyProfileVm(@Html.Raw(
        JsonConvert.SerializeObject(Model, 
            new JsonSerializerSettings() { 
                 ContractResolver = new CamelCasePropertyNamesContractResolver() 
        }).Replace("</script>", "</scripttag>")
    ))));
</script>

当然,如果你需要在多个地方使用它,你可以将这个逻辑转换为辅助/扩展方法,如:

public static class JavaScriptExtensions
{
    public static string SerializeAndEscapeScriptTags(this object model)
    {
        return JsonConvert.SerializeObject(model,
            new JsonSerializerSettings()
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver()
                }).Replace("</script>", "</scripttag>");
    }
}

并将其用于:

@using YourExtensionMethodsNamespace

<script type="text/javascript">
        $(document).ready(ko.applyBindings(new MyProfileVm(@Html.Raw(
            Model.SerializeAndEscapeScriptTags()))));
</script>

在Knockout视图模型的JavaScript端,您需要在使用前替换</script>标记:

var MyProfileVm = function(data) {
   //...
   this.aboutMe = ko.observable(
     // you need  `"</scr"+ "ipt>"` because of the above mentioned problem.
   data.aboutMe.replace(/<\/scripttag>/g, "</scr"+ "ipt>"));
}

当然你也可以为此创建一个辅助函数,如:

function fixScriptTags(data) {
    for(var prop in data) {
        if (typeof(data[prop]) == "string") {
            data[prop] = data[prop].replace(/<\/scripttag>/g, "</scr"+ "ipt>");
        }
        //todo check for complex property values and call fixScriptTags recursively
    } 
    return data;
}

并将其用于:

ko.applyBindings(new ViewModel(fixScriptTags(data)));

演示JSFiddle

答案 1 :(得分:1)

我遇到了类似的问题,它来自于使用knockout.js来获取<textarea>的输入,就像你一样。在“创建”部分,一切都很好,但是一旦我通过@Html.Raw(...)将数据放回到一个动作中,它就会包含打破json字符串的换行符和回车符。 所以我添加了这样的东西:

// Regex to replace all unescaped (single) backslashes in a string
private static Regex _regex = new Regex(@"(?<!\\)\\(?!\\)", RegexOptions.Compiled);

(我知道它不会处理“\\\”,但这不会出现在淘汰赛中)

然后我构建我的匿名类并执行此操作:

var coJson = JsonHelper.Serialize(co);
var coJsonEsc = _regex.Replace(coJson, @"\\")

也许这可以帮到你。我通过打破剃刀视图并查看字符串找到了它。 这个问题也出现在unesacped标签(\ t)和可能的其他转义序列中。