C # Как я могу вернуть свой базовый класс в веб-сервис - PullRequest
6 голосов
/ 12 мая 2010

У меня есть класс Car и производная SportsCar: Car
Как то так:

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


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

У меня есть веб-сервис с методами, возвращающими 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 произошла ошибка. ---> System.InvalidOperationException: тип wsBaseDerived.SportsCar не ожидался. Используйте атрибут XmlInclude или SoapInclude, чтобы указать типы, которые статически не известны.

Мне странно, что он не может сериализовать это как прямую машину, поскольку mycar - это машина.

Добавление 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 ]

2 голосов
/ 14 мая 2010

Я бы реализовал конструктор копирования в базовом классе.

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

Затем вы можете вернуть новый Автомобиль на основе SportsCar в метод GetMyCar. Я думаю, что таким образом ясно выразить намерение метода.

    public Car GetMyCar()
    {
        var sportsCar = new SportsCar { GirlFriend = "JLo", TopSpeed = 300 };
        return new Car(sportsCar);
    }
1 голос
/ 12 мая 2010

Сделайте это:

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

Причина в том, что XMLSerializer проверяет тип объекта GetType () и ожидает, что он будет таким же, как объявленный.

Я знаю, что это боль, но я не знаю альтернативы.

0 голосов
/ 12 мая 2010

Если вы хотите, чтобы всегда сериализовалось как "Автомобиль" вместо "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>
0 голосов
/ 12 мая 2010

Другие комментарии и ответы здесь заставили меня задуматься, и если мне нужно создать метод Mapper, пусть будет так:

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

}

и веб-метод:

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

Это работает как ожидалось:

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

Это противоречит цели иметь производный объект, на мой взгляд, но пока кто-то не придет с другим решением, таким, каким я буду летать ...

0 голосов
/ 12 мая 2010

Попробуйте WCF, есть [KnownType].

Однако не знаю, возможно ли это с помощью oldskool SOAP webservices.

0 голосов
/ 12 мая 2010

Просто удар, но ты пробовал это? В ролях по возвращении.

[WebMethod]
public Car GetMyCar()
{
    Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
    return (Car)mycar;
}
0 голосов
/ 12 мая 2010

Либо используйте XmlIgnoreAttribute для атрибутов, которые вы хотите игнорировать. Или еще более болезненным способом было бы реализовать пользовательскую сериализацию для ваших атрибутов.

Удачи.

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