Json.Net:HTML辅助方法不能再生 [英] Json.Net: Html Helper Method not regenerating

查看:152
本文介绍了Json.Net:HTML辅助方法不能再生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我运行到哪里我创建了一个ASP.NET MVC HTML辅助方法,不被再生每次调用时出现问题。

I'm running into a problem where an ASP.NET MVC html helper method I created is not being "regenerated" each time it is called.

辅助方法的目​​的是创建在angularjs框架中使用JavaScript对象。例如,这里有一个code段在使用辅助方法(从HTML页面的脚本标签中调用):

The purpose of the helper method is to create Javascript objects to be used in an angularjs framework. For example, here's a code snippet where the helper method is used (called from within a script tag of an html page):

var app = angular.module( "appName", ["ui.bootstrap"] );

app.controller( 'appCtrl', function( $scope ) {
    $scope.model = @Html.ToJavascript( Model, new string[] { "FirstName", "LastName", "ID", "Role" } );
} );

模式是一种具有多种属性的类的实例,但我只想名字,姓氏,ID和角色来获得序列化的JavaScript对象。

Model is an instance of a class which has a variety of properties, but I only want FirstName, LastName, ID and Role to get serialized to a javascript object.

该ToJavascript()辅助方法是在统计的类定义如下:

The ToJavascript() helper method is defined in a statis class as follows:

   public static HtmlString ToJavascript( this HtmlHelper helper, object toConvert, string[] includedFields = null, Formatting formatting = Formatting.Indented, ReferenceLoopHandling loopHandling = ReferenceLoopHandling.Ignore )
    {
        using( var stringWriter = new StringWriter() )
        using( var jsonWriter = new JsonTextWriter( stringWriter ) )
        {
            var serializer = new JsonSerializer()
            {
                // Let's use camelCasing as is common practice in JavaScript
                ContractResolver = new SpecificFieldsResolver( includedFields ),
                Formatting = formatting,
                ReferenceLoopHandling = loopHandling,
            };

            // We don't want quotes around object names
            jsonWriter.QuoteName = false;
            serializer.Serialize( jsonWriter, toConvert );

            return new HtmlString( stringWriter.ToString() );
        }
    }

这利用Json.NET做实际的序列化。

This utilizes Json.NET to do the actual serialization.

一个Json.NET的许多很酷的功能是,它允许您定义,对飞,哪些字段被序列化。这就是SpecificFieldsResolver做什么。我如下定义它:

One of the many cool features of Json.NET is that it lets you define, on the fly, which fields get serialized. That's what the SpecificFieldsResolver does. I've defined it as follows:

public class SpecificFieldsResolver : CamelCasePropertyNamesContractResolver
{
    private string[] _included;

    public SpecificFieldsResolver( string[] included )
    {
        _included = included;
    }

    protected override JsonProperty CreateProperty( MemberInfo member, MemberSerialization memberSerialization )
    {
        JsonProperty prop = base.CreateProperty( member, memberSerialization );

        bool inclField = ( _included == null )
            || _included.Contains( member.Name, StringComparer.CurrentCultureIgnoreCase );

        prop.ShouldSerialize = obj => inclField;

        return prop;
    }
}

什么是困惑我的是,CreateProperty()被调用的方式。特别是,它似乎只获取对象的每个类型被序列化调用一次。

What's confusing me is the way that CreateProperty() gets called. Specifically, it seems to only get called once for each type of object being serialized.

这是一个问题,因为在另一个CSHTML文件我有另一个调用这是试图序列相同类型的对象ToJavascript(),但与不同的领域是从序列输出:

That's a problem because in another cshtml file I have another call to ToJavascript() which is attempting to serialize the same type of object, but with different fields to be output from the serialization:

var app = angular.module( "app2Name", ["ui.bootstrap"] );

app.controller( 'app2Ctrl', function( $scope ) {
    $scope.model = @Html.ToJavascript( Model, new string[] { "FirstName", "LastName", "ID", "Role", "Category", "VoterID" } );
} );

类别和VoterID也有效类字段。但ToJavascript()不seralize他们。相反,它只是序列化),在第一次调用ToJavascript(定义的字段...即使是呼叫发生在不同的CSHTML文件。这是因为如果SpecificFieldsResolver记得JsonProperty对象它创建。

Category and VoterID are also valid class fields. But ToJavascript() doesn't seralize them. Instead, it only serializes the fields defined in the first call to ToJavascript()...even though that call takes place in a different cshtml file. It's as if SpecificFieldsResolver remembers the JsonProperty objects it creates.

思考?

更新

感谢名单,以DBC为准确诊断什么是错的,并提出一种解决方法。我adapated稍微因为我靠Json.NET的驼峰域名解析在几个解析器:

Thanx to dbc for diagnosing exactly what was wrong and suggesting a workaround. I adapated it slightly because I rely on Json.NET's camel case name resolution in several resolvers:

public class CamelCaseNameMapper : CamelCasePropertyNamesContractResolver
{
    public string ToCamelCase( string propertyName )
    {
        return ResolvePropertyName( propertyName );
    }
}

public class MaoDefaultContractResolver : DefaultContractResolver
{
    private CamelCaseNameMapper _mapper = new CamelCaseNameMapper();

    protected override string ResolvePropertyName( string propertyName )
    {
        return _mapper.ToCamelCase( propertyName );
    }

}

现在每一个解析器,比如我SpecificFieldsResolver,从MaoDefaultContractResolver派生自动继承骆驼外壳,但避免了缓存问题DBC标识。

Now every resolver, such as my SpecificFieldsResolver, which derives from MaoDefaultContractResolver automatically inherits camel casing but avoids the caching problem the dbc identified.

推荐答案

这似乎是一个bug与<一个href=\"https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs\"相对=nofollow> CamelCasePropertyNamesContractResolver 。它的基类,<一个href=\"http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Serialization_DefaultContractResolver.htm\"相对=nofollow> DefaultContractResolver ,有两个构造函数:一个<一个href=\"http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor.htm\"相对=nofollow>参数的构造函数和<一个href=\"http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm\"相对=nofollow> DefaultContractResolver(布尔) 版本(刚刚在Json.NET 7.0过时)。该参数具有以下含义:

This appears to be a bug with CamelCasePropertyNamesContractResolver. Its base class, DefaultContractResolver, has two constructors: a parameterless constructor, and a DefaultContractResolver (Boolean) version (just made obsolete in Json.NET 7.0). This parameter has the following meaning:

shareCache

shareCache


      
  • 类型:System.Boolean

  • Type: System.Boolean

如果设置为true, DefaultContractResolver 将使用一个缓存与同类型其他解析器共享。共享缓存将显著改善与多个实例解析性能,因为昂贵的反射将只发生一次。此设置可能会导致意外的行为,如果解析器的不同实例是假设产生不同的结果。如果设置为false,强烈建议重用 DefaultContractResolver JsonSerializer 实例。

If set to true the DefaultContractResolverwill use a cached shared with other resolvers of the same type. Sharing the cache will significantly improve performance with multiple resolver instances because expensive reflection will only happen once. This setting can cause unexpected behavior if different instances of the resolver are suppose to produce different results. When set to false it is highly recommended to reuse DefaultContractResolver instances with the JsonSerializer.

默认为

不幸的是,在<一href=\"https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs\"相对=nofollow>为 CamelCasePropertyNamesContractResolver >的值设置为true:

Unfortunately, the default constructor for CamelCasePropertyNamesContractResolver sets the value to true:

public class CamelCasePropertyNamesContractResolver : DefaultContractResolver
{
    /// <summary>
    /// Initializes a new instance of the <see cref="CamelCasePropertyNamesContractResolver"/> class.
    /// </summary>
    public CamelCasePropertyNamesContractResolver()
#pragma warning disable 612,618
        : base(true)
#pragma warning restore 612,618
    {
    }
}

此外,还与 shareCache 选项没有第二个构造函数。这打破你的 SpecificFieldsResolver

Further, there is no second constructor with the shareCache option. This breaks your SpecificFieldsResolver.

作为一种解决方法,你可以从 DefaultContractResolver 获得您的解析器,并使用杂牌 CamelCasePropertyNamesContractResolver 纯映射属性名称:

As a workaround, you could derive your resolver from DefaultContractResolver and use a kludge CamelCasePropertyNamesContractResolver purely to map the property names:

public class SpecificFieldsResolver : DefaultContractResolver
{
    class CamelCaseNameMapper : CamelCasePropertyNamesContractResolver
    {
        // Purely to make the protected method public.
        public string ToCamelCase(string propertyName)
        {
            return ResolvePropertyName(propertyName);
        }
    }
    readonly CamelCaseNameMapper nameMapper = new CamelCaseNameMapper();

    protected override string ResolvePropertyName(string propertyName)
    {
        return nameMapper.ToCamelCase(propertyName);
    }

    private string[] _included;

    public SpecificFieldsResolver(string[] included)
    {
        _included = included;
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty prop = base.CreateProperty(member, memberSerialization);

        bool inclField = (_included == null)
            || _included.Contains(member.Name, StringComparer.CurrentCultureIgnoreCase);

        prop.ShouldSerialize = obj => inclField;

        return prop;
    }
}

这篇关于Json.Net:HTML辅助方法不能再生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆