1

在一个项目中,我使用 LINQ to SQL 和 WCF。

我有以下单表继承:

单表继承

当我调用GetMediaForItem返回ItemMedia(基类型)对象列表的 WCF 方法 () 时,我得到了异常A first chance exception of type 'System.Runtime.Serialization.SerializationException' occurred in System.Runtime.Serialization.dll

但是当我调用一个 WCF 方法 ( GetYouTubeVideosForItem) 来返回一个YouTubeVideo's 列表(派生类型之一)时,它工作正常。

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MediaService : IMediaService
{
    ...

    // this throws a System.Runtime.Serialization.SerializationException
    public List<ItemMedia> GetMediaForItem(int itemId)
    {
        using (var context = _db.CreateContext())
        {
            context.DeferredLoadingEnabled = false;

            return (from i in context.ItemMedias
                    where i.ItemID == itemId
                    orderby i.Order
                    select i).ToList();
        }
    }

    // this works fine
    public List<YouTubeVideo> GetYouTubeVideosForItem(int itemId)
    {
        using (var context = _db.CreateContext())
        {
            context.DeferredLoadingEnabled = false;

            return (from i in context.ItemMedias.OfType<YouTubeVideo>()
                    where i.ItemID == itemId
                    orderby i.Order
                    select i).ToList();
        }
    }
}

服务接口:

[ServiceContract]
public interface IMediaService
{
    [OperationContract]
    [WebInvoke(
        Method = "GET",
        UriTemplate = "Media?itemId={itemId}",
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Bare
    )]
    List<ItemMedia> GetMediaForItem(int itemId);

    [OperationContract]
    [WebInvoke(
        Method = "GET",
        UriTemplate = "YouTubeVideos?itemId={itemId}",
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Bare
    )]
    List<YouTubeVideo> GetYouTubeVideosForItem(int itemId);
}

以下是生成的模型:

[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.ItemMedia")]
[global::System.Data.Linq.Mapping.InheritanceMappingAttribute(Code="media", Type=typeof(ItemMedia), IsDefault=true)]
[global::System.Data.Linq.Mapping.InheritanceMappingAttribute(Code="video", Type=typeof(YouTubeVideo))]
[global::System.Data.Linq.Mapping.InheritanceMappingAttribute(Code="image", Type=typeof(Image))]
public partial class ItemMedia : INotifyPropertyChanging, INotifyPropertyChanged
{

    private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);

    private int _ID;

    private int _ItemID;

    private string _MediaType;

    private int _Order;

    private System.Nullable<System.DateTime> _AddedOn;

    private System.Nullable<int> _AddedBy;

    private System.Nullable<System.DateTime> _ChangedOn;

    private System.Nullable<int> _ChangedBy;

    private EntityRef<Item> _Item;

#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnIDChanging(int value);
partial void OnIDChanged();
partial void OnItemIDChanging(int value);
partial void OnItemIDChanged();
partial void OnMediaTypeChanging(string value);
partial void OnMediaTypeChanged();
partial void OnOrderChanging(int value);
partial void OnOrderChanged();
partial void OnAddedOnChanging(System.Nullable<System.DateTime> value);
partial void OnAddedOnChanged();
partial void OnAddedByChanging(System.Nullable<int> value);
partial void OnAddedByChanged();
partial void OnChangedOnChanging(System.Nullable<System.DateTime> value);
partial void OnChangedOnChanged();
partial void OnChangedByChanging(System.Nullable<int> value);
partial void OnChangedByChanged();
#endregion

    public ItemMedia()
    {
        this._Item = default(EntityRef<Item>);
        OnCreated();
    }

    [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
    public int ID
    {
        get
        {
            return this._ID;
        }
        set
        {
            if ((this._ID != value))
            {
                this.OnIDChanging(value);
                this.SendPropertyChanging();
                this._ID = value;
                this.SendPropertyChanged("ID");
                this.OnIDChanged();
            }
        }
    }

    [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ItemID", DbType="Int")]
    public int ItemID
    {
        get
        {
            return this._ItemID;
        }
        set
        {
            if ((this._ItemID != value))
            {
                if (this._Item.HasLoadedOrAssignedValue)
                {
                    throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
                }
                this.OnItemIDChanging(value);
                this.SendPropertyChanging();
                this._ItemID = value;
                this.SendPropertyChanged("ItemID");
                this.OnItemIDChanged();
            }
        }
    }

    [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_MediaType", DbType="VarChar(10)", IsDiscriminator=true)]
    public string MediaType
    {
        get
        {
            return this._MediaType;
        }
        set
        {
            if ((this._MediaType != value))
            {
                this.OnMediaTypeChanging(value);
                this.SendPropertyChanging();
                this._MediaType = value;
                this.SendPropertyChanged("MediaType");
                this.OnMediaTypeChanged();
            }
        }
    }

    [global::System.Data.Linq.Mapping.ColumnAttribute(Name="[Order]", Storage="_Order", DbType="Int NOT NULL")]
    public int Order
    {
        get
        {
            return this._Order;
        }
        set
        {
            if ((this._Order != value))
            {
                this.OnOrderChanging(value);
                this.SendPropertyChanging();
                this._Order = value;
                this.SendPropertyChanged("Order");
                this.OnOrderChanged();
            }
        }
    }

    [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_AddedOn", DbType="DateTime")]
    public System.Nullable<System.DateTime> AddedOn
    {
        get
        {
            return this._AddedOn;
        }
        set
        {
            if ((this._AddedOn != value))
            {
                this.OnAddedOnChanging(value);
                this.SendPropertyChanging();
                this._AddedOn = value;
                this.SendPropertyChanged("AddedOn");
                this.OnAddedOnChanged();
            }
        }
    }

    [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_AddedBy", DbType="Int")]
    public System.Nullable<int> AddedBy
    {
        get
        {
            return this._AddedBy;
        }
        set
        {
            if ((this._AddedBy != value))
            {
                this.OnAddedByChanging(value);
                this.SendPropertyChanging();
                this._AddedBy = value;
                this.SendPropertyChanged("AddedBy");
                this.OnAddedByChanged();
            }
        }
    }

    [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ChangedOn", DbType="DateTime")]
    public System.Nullable<System.DateTime> ChangedOn
    {
        get
        {
            return this._ChangedOn;
        }
        set
        {
            if ((this._ChangedOn != value))
            {
                this.OnChangedOnChanging(value);
                this.SendPropertyChanging();
                this._ChangedOn = value;
                this.SendPropertyChanged("ChangedOn");
                this.OnChangedOnChanged();
            }
        }
    }

    [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ChangedBy", DbType="Int")]
    public System.Nullable<int> ChangedBy
    {
        get
        {
            return this._ChangedBy;
        }
        set
        {
            if ((this._ChangedBy != value))
            {
                this.OnChangedByChanging(value);
                this.SendPropertyChanging();
                this._ChangedBy = value;
                this.SendPropertyChanged("ChangedBy");
                this.OnChangedByChanged();
            }
        }
    }
            [global::System.Data.Linq.Mapping.AssociationAttribute(Name="Item_ItemMedia", Storage="_Item", ThisKey="ItemID", OtherKey="ID", IsForeignKey=true)]
    public Item Item
    {
        get
        {
            return this._Item.Entity;
        }
        set
        {
            Item previousValue = this._Item.Entity;
            if (((previousValue != value) 
                        || (this._Item.HasLoadedOrAssignedValue == false)))
            {
                this.SendPropertyChanging();
                if ((previousValue != null))
                {
                    this._Item.Entity = null;
                    previousValue.ItemMedias.Remove(this);
                }
                this._Item.Entity = value;
                if ((value != null))
                {
                    value.ItemMedias.Add(this);
                    this._ItemID = value.ID;
                }
                else
                {
                    this._ItemID = default(int);
                }
                this.SendPropertyChanged("Item");
            }
        }
    }

    public event PropertyChangingEventHandler PropertyChanging;

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void SendPropertyChanging()
    {
        if ((this.PropertyChanging != null))
        {
            this.PropertyChanging(this, emptyChangingEventArgs);
        }
    }

    protected virtual void SendPropertyChanged(String propertyName)
    {
        if ((this.PropertyChanged != null))
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public partial class YouTubeVideo : ItemMedia
{

    private string _YouTubeVideoID;

#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnYouTubeVideoIDChanging(string value);
partial void OnYouTubeVideoIDChanged();
#endregion

    public YouTubeVideo()
    {
        OnCreated();
    }

    [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_YouTubeVideoID", DbType="NVarChar(15)")]
    public string YouTubeVideoID
    {
        get
        {
            return this._YouTubeVideoID;
        }
        set
        {
            if ((this._YouTubeVideoID != value))
            {
                this.OnYouTubeVideoIDChanging(value);
                this.SendPropertyChanging();
                this._YouTubeVideoID = value;
                this.SendPropertyChanged("YouTubeVideoID");
                this.OnYouTubeVideoIDChanged();
            }
        }
    }
}

public partial class Image : ItemMedia
{

    private string _ImageName;

    private string _ImageData;

#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnImageNameChanging(string value);
partial void OnImageNameChanged();
partial void OnImageDataChanging(string value);
partial void OnImageDataChanged();
#endregion

    public Image()
    {
        OnCreated();
    }

    [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ImageName", DbType="NVarChar(MAX)")]
    public string ImageName
    {
        get
        {
            return this._ImageName;
        }
        set
        {
            if ((this._ImageName != value))
            {
                this.OnImageNameChanging(value);
                this.SendPropertyChanging();
                this._ImageName = value;
                this.SendPropertyChanged("ImageName");
                this.OnImageNameChanged();
            }
        }
    }

    [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ImageData", DbType="NVarChar(MAX)")]
    public string ImageData
    {
        get
        {
            return this._ImageData;
        }
        set
        {
            if ((this._ImageData != value))
            {
                this.OnImageDataChanging(value);
                this.SendPropertyChanging();
                this._ImageData = value;
                this.SendPropertyChanged("ImageData");
                this.OnImageDataChanged();
            }
        }
    }
}
4

1 回答 1

1

WCF 以及 .NET 中的所有序列化过程都有一些与实现多个类的对象有关的技巧。我相信在这种情况下,您会发现仅使用单个对象的类似异常。

原因是 theYouTubeVideo是一个ItemMedia项目 - 即从您的方法返回 a 是有效的YouTubeVideo- 但如果我们要调用GetType该项目,它会给出 a System.Typeof YouTubeVideo。类型不匹配,这会混淆反序列化过程。

当一个对象在 .NET 中序列化时,结果包括对象的给定类型 - 将其视为框架将对象重新水合为正确类型的指令 - 在这种情况下,类型将是YouTubeVideo(因为这就是GetType返回的内容) . 您的反序列化代码需要一个ItemMedia类型对象,因此它会抱怨您所看到的异常。

您可以使用KnownTypeAttribute. 在这种情况下,您可能希望将属性添加到ItemMedia类中,以便反序列化器了解YouTubeVideo已知是该类型的扩展。

[KnownType(typeof(YouTubeVideo))]
public partial class ItemMedia
{

将其放在部分类中而不是您生成的代码中,因为如果将其保留在生成的类中,它可能会被未来的代码生成破坏。

于 2013-08-27T12:40:26.703 回答