加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – 使用MVC 4.0 Web Api的NewtonSoft json Contract

发布时间:2020-12-16 09:38:27 所属栏目:asp.Net 来源:网络整理
导读:我正在尝试创建一个条件ContractResolver,以便我可以根据Web请求/控制器操作不同地控制序列化. 例如,在我的用户控制器中,我想序列化我的用户的所有属性,但是我可能只序列化基本类型的一些相关对象.但是,如果我去公司控制器,我想序列化公司的所有属性,但可能
我正在尝试创建一个条件ContractResolver,以便我可以根据Web请求/控制器操作不同地控制序列化.

例如,在我的用户控制器中,我想序列化我的用户的所有属性,但是我可能只序列化基本类型的一些相关对象.但是,如果我去公司控制器,我想序列化公司的所有属性,但可能只是用户的原始属性(因此我不想使用数据注释或应该序列化函数.

因此,查看自定义的ContractResolver页面,我创建了自己的.
http://james.newtonking.com/projects/json/help/index.html?topic=html/ContractResolver.htm

看起来像这样

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

然后在GetUsers的web api控制器操作中,我这样做

public dynamic GetUsers()
{
    List<User> Users = db.Users.ToList();
    List<string> RoleList = new List<string>();
    RoleList.Add("UsersInRole");
    List<string> CompanyList = new List<string>();
    CompanyList.Add("CompanyAccesses");
    CompanyList.Add("ArchivedMemberships");
    CompanyList.Add("AddCodes");

    Dictionary<string,List<string>> IgnoreList = new Dictionary<string,List<string>>();
    IgnoreList.Add("Role",RoleList);
    IgnoreList.Add("Company",CompanyList);
    GlobalConfiguration
            .Configuration
            .Formatters.JsonFormatter
            .SerializerSettings
            .ContractResolver = new IgnoreListContractResolver(IgnoreList);

    return new { List = Users,Status = "Success" };
}

因此,在调试时,我看到我的合同解析器运行并返回正确的属性,但返回浏览器的Json仍然包含我从列表中删除的属性的条目.

任何想法我缺少什么或如何进入webapi控制器中的Json序列化步骤.

*更新**
我应该补充一点,这是一个MVC4项目,它同时具有MVC控制器和webapi控制器. User,Company和Role对象是从EF5加载的对象(首先由代码创建).有问题的控制器是一个web api控制器.不知道为什么这很重要,但我在一个干净的WebApi项目(没有EF5)而不是MVC项目中尝试了这个,并且它按预期工作.这有助于确定问题的所在位置吗?

谢谢

*更新2 **
在同一个MVC4项目中,我为Object类创建了一个名为ToJson的扩展方法.它使用Newtonsoft.Json.JsonSerializer来序列化我的实体.这很简单.

public static string ToJson(this object o,Dictionary<string,List<string>> IgnoreList)
{
    JsonSerializer js = JsonSerializer.Create(new Newtonsoft.Json.JsonSerializerSettings()
    {
        Formatting = Formatting.Indented,DateTimeZoneHandling = DateTimeZoneHandling.Utc,ContractResolver = new IgnoreListContractResolver(IgnoreList),ReferenceLoopHandling = ReferenceLoopHandling.Ignore  
    });

    js.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());

    var jw = new StringWriter();
    js.Serialize(jw,o);
    return jw.ToString();

}

然后在MVC动作中我创建一个像这样的json字符串.

model.jsonUserList = db.Users.ToList().ToJson(IgnoreList);

创建忽略列表的位置与我之前的帖子完全相同.我再次看到合同解析器运行并正确限制属性列表,但输出json字符串仍然包含所有内容(包括我从列表中删除的属性).这有帮助吗?我必须做错事,现在好像它不是MVC或web api框架.这可能与EF交互/代理/等有关.任何想法将不胜感激.

谢谢

*更新3 ***

消除过程和更彻底的调试使我意识到EF 5动态代理正在弄乱我的序列化和ContractResolver检查类型名称匹配.所以这是我更新的IgnoreListContractResolver.在这一点上,我只是在寻找更好的方法或者我做一些可怕的事情.我知道这是为了直接使用我的EF对象而不是DTO而跳过很多箍,但最后我发现这个解决方案非常灵活.

public class IgnoreListContractResolver : CamelCasePropertyNamesContractResolver
{
    private readonly Dictionary<string,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;
    }
}

解决方法

我认为如果你使用Type而不是string作为忽略列表的键类型可能会有所帮助.因此,您可以避免命名问题(在不同的命名空间中具有相同名称的多个类型),并且您可以使用继承.我不熟悉EF5和代理,但我想代理类派生自你的实体类.因此,您可以检查 Type.IsAssignableFrom()而不是仅仅检查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;
}

然后必须像这样创建忽略列表(我还使用了短语法来创建列表和字典):

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

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读