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

F#, Serialize dynamically generated objects with WebAPI

我正在尝试在 F# 中创建 Web API 控制器,其中 returns 对象来自 Entity Framework。 SharpObject 和 SharpContext 分别是我在一个c#项目中定义的对象和DbContext。

/// 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>

这是带有 SerializableAttribute 的 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# 中显示的最佳方法是什么?

发生这种情况是因为您从 EF 获得的对象 不是 ,实际上是 SharpObject 类型,而是那种可怕命名的类型,SharpObject继承。这种类型称为"proxy",由EF动态生成,以提供某些服务(例如延迟加载,见下文)。

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

您可以尝试的一种临时的创可贴式修复方法是从您的实体中删除 virtual 关键字(无论如何,为什么要将它们放在那里?)。 virtual 关键字的存在导致 EF 生成代理类型。缺少 virtual,将不会生成任何代理,从而使 XML 序列化器快乐。
但是,一旦您扩展模型以包含具有延迟加载的导航属性,这将不起作用。这些属性,你必须设为虚拟,否则延迟加载将无法工作。

所以正确的修复是不要对面向数据库的 DTO 和面向客户端的 DTO 使用相同的类型。使用不同的类型。
为这两个目的使用相同的类型乍一看似乎 "convenient",但这条路很快会导致许多问题。您已经发现的小技术问题之一。但即使没有这些,从概念上讲,您几乎永远也不想直接将您的数据库记录提供给不受信任的用户。一些可能的后果包括安全漏洞、分解错误的 UI 代码、分解错误的数据库结构、性能问题等等。

坏主意。别这样。

P.S。这实际上与 F# 没有任何关系。