我正在尝试在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>
这是带有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#中显示的最佳方法是什么?
答案 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#无关。