F#,使用WebAPI序列化动态生成的对象

时间:2015-09-16 01:30:57

标签: f# asp.net-web-api2

我正在尝试在F#中创建Web API控制器,它从Entity Framework返回对象。 SharpObject和SharpContext是我的对象和DbContext,分别在c#项目中定义。

/// Retrieves values.
[<RoutePrefix("api2/values")>]
type ValuesController() = 
    inherit ApiController()
    let values = [| "value1"; "value2" |]

    /// Gets all values.
    [<Route("")>]
    member x.Get() : IEnumerable<SharpObject> = 
        use context = new SharpContext()
        context.SharpObjects.ToList() :> IEnumerable<SharpObject>

这是带有Seri​​alizableAttribute的SharpObject。

[Serializable]
public class SharpObject
{
    [Key]
    public virtual int Id { get; set; }
    public virtual string Description { get; set; }
}

我得到的错误是这样的: The type System.Data.Entity.DynamicProxies.SharpObject_3A697B5C46C0BF76858FEAFC93BFED36DD8D4CA2CEACBB178D2D3C38BB2D2052 was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

当我使用ILSpy对其进行反编译时,它看起来像这样:

[Route("")]
public IEnumerable<SharpObject> Get()
{
    SharpContext context = new SharpContext();
    IEnumerable<SharpObject> result;
    try
    {
        result = (IEnumerable<SharpObject>)context.SharpObjects.ToList<SharpObject>();
    }
    finally
    {
        IDisposable disposable = context as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }
    return result;
}

让我的列表在f#中显示的最佳方法是什么?

1 个答案:

答案 0 :(得分:2)

这是因为您从EF获得的对象实际上是而不是,类型为SharpObject,而是继承的scarily命名类型>来自SharpObject。这种类型称为&#34;代理&#34;并且由EF动态生成,以便提供某些服务(例如延迟加载,见下文)。

因为您的操作被声明为返回IEnumerable<SharpObject>,所以默认的WebAPI的XML序列化程序期望找到该类型的对象,因此在找到不同类型的对象时会正确地抱怨。

您可以尝试的一种临时的,绑定式的修补方法是从您的实体中删除virtual个关键字(为什么还要在那里使用它们?)。存在virtual关键字会导致EF生成代理类型。如果没有virtual,则不会生成任何代理,从而使XML序列化程序感到满意 但是,一旦扩展模型以包含延迟加载的导航属性,这将不起作用。这些属性,你必须进行虚拟,否则延迟加载将无法正常工作。

因此正确的修复不会对面向数据库的DTO和面向客户端的DTO使用相同的类型。使用不同的类型 为这两个目的使用相同的类型可能看起来很方便&#34;起初,但这条道路很快就会导致很多问题。您已经发现的一个小技术问题。但即使没有这些,从概念上讲,您几乎从未想过直接向不受信任的用户提供您的数据库记录。一些可能的后果包括安全漏洞,严重因素的UI代码,严重因素的数据库结构,性能问题等。

糟糕的主意。不要这样做。

P.S。这实际上与F#无关。