Asp.net mvc 带有MVC 4.0 Web Api的NewtonSoft json契约解析器未按预期生成输出

Asp.net mvc 带有MVC 4.0 Web Api的NewtonSoft json契约解析器未按预期生成输出,asp.net-mvc,json,asp.net-mvc-4,asp.net-web-api,json.net,Asp.net Mvc,Json,Asp.net Mvc 4,Asp.net Web Api,Json.net,我正在尝试创建一个条件ContractResolver,以便根据web请求/控制器操作以不同的方式控制序列化 例如,在我的用户控制器中,我想序列化用户的所有属性,但某些相关对象可能只序列化基本类型。但是如果我转到我的公司控制器,我想序列化公司的所有属性,但可能只序列化用户的原始属性(因此我不想使用DataAnnotation或shouldserialize函数) 因此,查看自定义ContractResolver页面,我创建了自己的。 看起来像这样 public class IgnoreList

我正在尝试创建一个条件ContractResolver,以便根据web请求/控制器操作以不同的方式控制序列化

例如,在我的用户控制器中,我想序列化用户的所有属性,但某些相关对象可能只序列化基本类型。但是如果我转到我的公司控制器,我想序列化公司的所有属性,但可能只序列化用户的原始属性(因此我不想使用DataAnnotation或shouldserialize函数)

因此,查看自定义ContractResolver页面,我创建了自己的。

看起来像这样

public class IgnoreListContractResolver : DefaultContractResolver
{
    private readonly Dictionary<string, List<string>> IgnoreList;

    public IgnoreListContractResolver(Dictionary<string, List<string>> i)
    {
        IgnoreList = i;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        List<JsonProperty> properties = base.CreateProperties(type, memberSerialization).ToList();

        if(IgnoreList.ContainsKey(type.Name))
        {
            properties.RemoveAll(x => IgnoreList[type.Name].Contains(x.PropertyName));                
        }
        return properties;
    }
}
忽略列表的创建与我之前的文章完全相同。我再次看到契约解析器运行并正确限制属性列表,但输出json字符串仍然包含所有内容(包括我从列表中删除的属性)。这有帮助吗?我一定是做错了什么,现在看来它不是MVC或web api框架。这可能与EF交互/代理等有关。任何想法都将不胜感激

谢谢


*更新3***

消除过程和更彻底的调试使我意识到EF 5动态代理弄乱了我的序列化和ContractResolver类型名称匹配检查。因此,这是我更新的IgnoreListContractResolver。此时,我正在寻找更好的方法的意见,或者我是否做了一些糟糕的事情。我知道这只是为了直接使用我的EF对象而不是DTO,但最终我发现这个解决方案非常灵活

public class IgnoreListContractResolver : CamelCasePropertyNamesContractResolver
{
    private readonly Dictionary<string, List<string>> IgnoreList;

    public IgnoreListContractResolver(Dictionary<string, List<string>> i)
    {
        IgnoreList = i;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        List<JsonProperty> properties = base.CreateProperties(type, memberSerialization).ToList();

        string typename = type.Name;
        if(type.FullName.Contains("System.Data.Entity.DynamicProxies.")) {
            typename = type.FullName.Replace("System.Data.Entity.DynamicProxies.", "");
            typename = typename.Remove(typename.IndexOf('_'));
        }

        if (IgnoreList.ContainsKey(typename))
        {
            //remove anything in the ignore list and ignore case because we are using camel case for json
            properties.RemoveAll(x => IgnoreList[typename].Contains(x.PropertyName, StringComparer.CurrentCultureIgnoreCase));
        }
        return properties;
    }
} 
公共类IgnoreListContractResolver:CamelCasePropertyNamesContractResolver
{
私有只读字典忽略列表;
公共IgnoreListContractResolver(字典i)
{
IgnoreList=i;
}
受保护的重写IList CreateProperties(类型类型,MemberSerialization MemberSerialization)
{
List properties=base.CreateProperties(type,memberSerialization.ToList();
字符串typename=type.Name;
if(type.FullName.Contains(“System.Data.Entity.DynamicProxies”)){
typename=type.FullName.Replace(“System.Data.Entity.DynamicProxies.”,“”);
typename=typename.Remove(typename.IndexOf(“”“);
}
if(IgnoreList.ContainsKey(typename))
{
//删除ignore列表中的任何内容,并忽略大小写,因为我们对json使用的是camel大小写
RemoveAll(x=>IgnoreList[typename]。包含(x.PropertyName,StringComparer.CurrentCultureIgnoreCase));
}
归还财产;
}
} 

我认为如果您对忽略列表的键类型使用
Type
而不是
string
,可能会有所帮助。因此,您可以避免命名问题(不同名称空间中具有相同名称的多个类型)您可以利用继承。我不熟悉EF5和代理,但我猜代理类源自您的实体类。因此,您可以检查而不仅仅是检查
typename
是否是忽略列表中的键

private readonly Dictionary<Type, List<string>> IgnoreList;

protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
    List<JsonProperty> properties = base.CreateProperties(type, memberSerialization).ToList();

    // look for the first dictionary entry whose key is a superclass of "type"
    Type key = IgnoreList.Keys.FirstOrDefault(k => k.IsAssignableFrom(type));

    if (key != null)
    {
        //remove anything in the ignore list and ignore case because we are using camel case for json
        properties.RemoveAll(x => IgnoreList[key].Contains(x.PropertyName, StringComparer.CurrentCultureIgnoreCase));
    }
    return properties;
}
专用只读字典忽略列表;
受保护的重写IList CreateProperties(类型类型,MemberSerialization MemberSerialization)
{
List properties=base.CreateProperties(type,memberSerialization.ToList();
//查找键为“type”超类的第一个字典条目
Type key=IgnoreList.Keys.FirstOrDefault(k=>k.IsAssignableFrom(Type));
if(key!=null)
{
//删除ignore列表中的任何内容,并忽略大小写,因为我们对json使用的是camel大小写
RemoveAll(x=>IgnoreList[key]。包含(x.PropertyName,StringComparer.CurrentCultureIgnoreCase));
}
归还财产;
}
然后必须像这样创建忽略列表(我还使用了创建列表和字典的简短语法):

var CompanyList=新列表{
“公司访问”,
“档案会员资格”,
“添加代码”
};
var IgnoreList=新字典{
//我刚才在这里用typeof(Company)替换了“Company”:
{typeof(Company),CompanyList}
};

请注意,如果使用上面的代码,请添加
typeof(object)
作为忽略列表的第一个键将导致每次都匹配此项,并且不会使用任何其他项!发生这种情况的原因是可以从其他类型分配类型为
object
的变量。

我喜欢您的更新,因为我从不喜欢用于确定键的字符串匹配。我又做了一次更改nge从这里开始使用PropertyUtil helper类,这样我就不必自己为属性名创建字符串。我不得不改回使用DefaultContractResolver,因为CamelCasePropertyNamesContractResolver会缓存每种类型的属性,因为这样做的全部目的是能够更改属性基于不起作用的输入参数。我能够重写ResolvePropertyName函数以返回camelcase,因此我的json/javascript工作正常。你有没有解决过这个问题?我们刚刚发现了同样的问题。仍在调查,但当我们从4.5 r4源代码构建时,我们没有这个问题。
model.jsonUserList = db.Users.ToList().ToJson(IgnoreList);
public class IgnoreListContractResolver : CamelCasePropertyNamesContractResolver
{
    private readonly Dictionary<string, List<string>> IgnoreList;

    public IgnoreListContractResolver(Dictionary<string, List<string>> i)
    {
        IgnoreList = i;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        List<JsonProperty> properties = base.CreateProperties(type, memberSerialization).ToList();

        string typename = type.Name;
        if(type.FullName.Contains("System.Data.Entity.DynamicProxies.")) {
            typename = type.FullName.Replace("System.Data.Entity.DynamicProxies.", "");
            typename = typename.Remove(typename.IndexOf('_'));
        }

        if (IgnoreList.ContainsKey(typename))
        {
            //remove anything in the ignore list and ignore case because we are using camel case for json
            properties.RemoveAll(x => IgnoreList[typename].Contains(x.PropertyName, StringComparer.CurrentCultureIgnoreCase));
        }
        return properties;
    }
} 
private readonly Dictionary<Type, List<string>> IgnoreList;

protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
    List<JsonProperty> properties = base.CreateProperties(type, memberSerialization).ToList();

    // look for the first dictionary entry whose key is a superclass of "type"
    Type key = IgnoreList.Keys.FirstOrDefault(k => k.IsAssignableFrom(type));

    if (key != null)
    {
        //remove anything in the ignore list and ignore case because we are using camel case for json
        properties.RemoveAll(x => IgnoreList[key].Contains(x.PropertyName, StringComparer.CurrentCultureIgnoreCase));
    }
    return properties;
}
var CompanyList = new List<string> {
    "CompanyAccesses",
    "ArchivedMemberships",
    "AddCodes"
};

var IgnoreList = new Dictionary<Type, List<string>> {
    // I just replaced "Company" with typeof(Company) here:
    { typeof(Company), CompanyList }
};