为什么在 web api 方法中返回接口时,我用接口值获取继承类的值

本文关键字:接口 获取 继承 web api 方法 返回 为什么 | 更新日期: 2023-09-27 18:37:19

>我有一个从接口继承的类,并且我从我的 web api 返回接口得到 methed,问题是我正在获取继承类的值作为 json 字符串。

这是界面

 public interface IFoo
    { 
    string A { get ;set ; } 
    string B { get ; set ; } 
    } 

继承的类

 public class Child : iFoo
    { 
    string A { get ; set ; } 
    string B { get ; set ; } 
    string C { get ; set ; } 
    string D { get ; set ; } 
    } 

然后我从控制器的 GetMethod 返回 IFoo

 public IFoo GetIFoo()
        {
        return  ChildInstance ; 
        }

当前结果给了我继承类的所有值,以及两个接口,但我只想要在 json 结果中的接口中实现的值。

为什么在 web api 方法中返回接口时,我用接口值获取继承类的值

当它命中 Json 序列化程序时,它并不关心方法的返回类型是什么。它只知道"我有这个对象,让我们看看我能用它做什么"。

如果希望序列化程序仅包含接口具有的属性,则最好为其指定一个仅具有接口具有的属性的对象。例如,您可以考虑使用自动映射器将值从ChildInstance复制到此新对象。

另一种方法更复杂 - 实现自己的序列化程序,以便 Json 序列化程序没有机会参与其中。

您的方法被收缩为返回实现IFoo的对象。它可以返回任何实现IFoo的对象,但不能返回Ifoo本身,因为你不能有一个接口的实例。所以它返回一个实例 Child .

然后,JSON 序列化程序将获得此Child实例,并使用反射来确定其属性。它找到A - D并因此对其进行序列化。

如果您只想A - B序列化,则必须返回仅实现 A - B 的类的实例。

说了这么多,如果你使用的是ASP MVC,那么请查看 http://www.creave.dk/post/2009/10/07/Excluding-properties-from-being-serialized-in-ASPNET-MVC-JsonResult.aspx。通过将类定义更改为

public class Child : iFoo
{ 
    string A { get ; set ; } 
    string B { get ; set ; }
    [ScriptIgnore]
    string C { get ; set ; } 
    [ScriptIgnore]
    string D { get ; set ; } 
} 

然后,您已指示 JSON 序列化程序仅序列化A - B

如果您不介意返回动态,则可以执行以下操作:

另一方面,如果您使用 json 序列化程序,这只能开箱即用,因此您必须指定"accept: application/json"才能正常工作。

public class Person
{
    public string Name { get; set; }
}
public class User : Person
{
    public string Title { get; set; }
    public string Email { get; set; }
}
public dynamic Get()
{
    var user = new User { Title = "Developer", Email = "foo@bar.baz", Name = "MyName" };
    return new { user.Name, user.Email };
}

如果控制器方法的返回类型是接口,还可以应用操作筛选器以仅序列化接口属性。这样,您始终与接口定义保持同步,而无需更改实现接口的类上的任何属性。

为此,您首先必须创建自定义InterfaceContractResolver协定解析器,如下所述:

    public class InterfaceContractResolver : DefaultContractResolver
    {
        private readonly Type _interfaceType;
        public InterfaceContractResolver(Type interfaceType)
        {
            _interfaceType = interfaceType;
        }
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            IList<JsonProperty> properties = base.CreateProperties(_interfaceType, memberSerialization);
            return properties;
        }
    }

然后添加一个操作筛选器(作为此处所述的属性,或者全局,如果您希望将其作为默认行为),该筛选器查看控制器方法的返回类型,并且它是使用上面定义的协定解析程序的接口:

    public class InterfaceFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            ObjectContent content = actionExecutedContext.Response.Content as ObjectContent;
            if (content != null)
            {
                Type returnType = actionExecutedContext.ActionContext.ActionDescriptor.ReturnType;
                if (returnType.IsInterface && content.Formatter is JsonMediaTypeFormatter)
                {
                    var formatter = new JsonMediaTypeFormatter
                        {
                            SerializerSettings =
                                {
                                    ContractResolver = new InterfaceContractResolver(returnType)
                                }
                        };
                    actionExecutedContext.Response.Content = new ObjectContent(content.ObjectType, content.Value, formatter);
                }
            }
        }
    }