C#如何在Web服务中返回我的基类

时间:2010-05-12 11:49:50

标签: c# serialization web-services base derived

我有一辆Car和一辆派生的SportsCar:Car
像这样:

public class Car
{
    public int TopSpeed{ get; set; }
}


public class SportsCar : Car
{
    public string GirlFriend { get; set; }
}

我有一个Web服务,其方法是返回Cars,即

[WebMethod]
public Car GetCar()
{
    return new Car() { TopSpeed = 100 };
}

它返回:

<Car>
<TopSpeed>100</TopSpeed>
</Car>

我还有另一种方法可以像这样返回汽车:

[WebMethod]
public Car GetMyCar()
{
    Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
    return mycar;
}

它编译好了一切,但是在调用它时我得到:
System.InvalidOperationException:生成XML文档时出错。 ---&GT; System.InvalidOperationException:不期望类型为wsBaseDerived.SportsCar。使用XmlInclude或SoapInclude属性指定静态未知的类型。

我觉得很奇怪,因为mycar是一辆汽车所以它无法将其序列化为直车。

在Web的WebMethod上添加XmlInclude会删除错误:

[WebMethod]
[XmlInclude(typeof(SportsCar))]
public Car GetMyCar()
{
    Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
    return mycar;
}

现在它返回:

<Car xsi:type="SportsCar">
    <TopSpeed>300</TopSpeed>
    <GirlFriend>JLo</GirlFriend>
</Car>

但我真的想要返回基类, 没有来自派生类的额外属性等。

在没有创建地图制作者等的情况下,这完全可以吗?

请说是;)

7 个答案:

答案 0 :(得分:2)

我会在基类中实现一个复制构造函数。

    public class Car
    {
        public int TopSpeed { get; set; }

        public Car(Car car)
        {
            TopSpeed = car.TopSpeed;
        }

        public Car()
        {
            TopSpeed = 100;
        }
    }

    public class SportsCar : Car
    {
        public string GirlFriend { get; set; }
    }

然后你可以在GetMyCar方法中根据SportsCar返回一辆新车。我认为这种方式清楚地表达了该方法的意图。

    public Car GetMyCar()
    {
        var sportsCar = new SportsCar { GirlFriend = "JLo", TopSpeed = 300 };
        return new Car(sportsCar);
    }

答案 1 :(得分:1)

这样做:

[WebMethod]
public Car GetMyCar()
{
    Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
    return new Car() {TopSpeed = mycar.TopSpeed};
}

原因是XMLSerializer检查对象的GetType()类型,并期望它与声明的对象相同。

我知道这是一种痛苦,但我不知道另一种选择。

答案 2 :(得分:0)

对要忽略的属性使用XmlIgnoreAttribute。或者更痛苦的方法是为你的属性实现custom serialization

祝你好运。

public class SportsCar : Car
{
  [XmlIgnoreAttribute]
  public string GirlFriend { get; set; }
}

答案 3 :(得分:0)

只是一个刺,但你试过这个吗?投下回报。

[WebMethod]
public Car GetMyCar()
{
    Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
    return (Car)mycar;
}

答案 4 :(得分:0)

尝试WCF,有[KnownType]。

但是,不知道是否可以使用oldskool SOAP webservices。

答案 5 :(得分:0)

这里的其他评论和答案让我思考,如果我需要制作一个Mapper方法,那就这样吧:

public class Car: ICloneable
{
    public int TopSpeed{ get; set; }
    public object Clone()
    {
        return new Car() { TopSpeed = this.TopSpeed };
    }

}

和webmethod:

[WebMethod]
public Car GetMyNewCar()
{
    Car mycar = new SportsCar() { GirlFriend = "HiLo", TopSpeed = 300 };            
    return (Car)mycar.Clone();
}

这可以按预期工作:

<Car>
    <TopSpeed>300</TopSpeed>
</Car>

这违背了我在视图中使用派生对象的目的,但是直到有人提出另一种解决方案,就像我将要飞行一样......

答案 6 :(得分:0)

如果您希望始终序列化为“Car”而不是“SportsCar”,请为其添加[XmlRoot("Car")]

public class Car {
  //stuff
}

[XmlRoot("Car")]
public class SportsCar {
  //Sporty stuff
}

编辑:像这样使用XmlSerializer:

XmlSerializer ser = new XmlSerializer(typeof(SportsCar));
SportsCar car = new SportsCar()
//stuff
ser.Serialize(Console.out, car)

你应该得到

<Car>
  <TopSpeed>300</TopSpeed>
  <GirlFriend>JLo</GirlFriend>
</Car>