【问题标题】:Passing an Entity Framework Context object to WCF将实体框架上下文对象传递给 WCF
【发布时间】:2011-12-11 06:19:57
【问题描述】:

我需要将 EF 中的 Context 对象传递给 WCF 方法。

通常,我在 WCF 方法中创建 Context 对象,并在方法调用结束之前将其处理掉,这对我的大多数方法都适用。

但是,我需要将 Context 对象(特别是 DBContext)从 MVC 控制器传递到我的特定 WCF 方法,因为我为某些查找表启用了缓存。我需要传递这个特定的 Context 对象(我在 Global.asax 文件的 Application_Start 方法中设置的那个),而不是我在上面的句子中所做的,因为我将这个特定的对象用于 SqlDependency。如果我尝试创建全新的 DBContext 对象,我将无法使用 SqlDependency,因为我会收到一条错误消息,通知我需要在调用数据库之前启用 SqlDependency。

问题是当我尝试启动我的 WCF 测试客户端工具时遇到以下错误(为简洁起见),我知道这与未正确声明 KnownType 属性(即 DBContext 对象)有关。请注意,WCF 项目编译得很好。由于我从未在我的 WCF 服务中使用过 KnownType,因此我需要一些有关此特定部分的帮助。它们都是简单类型(int、string 等)。

错误:无法从http://localhost:8732/Design_Time_Addresses/YeagerTechWcfService/YeagerTechWcfService/mex获取元数据

如果这是您使用的 Windows (R) Communication Foundation 服务 有访问权限,请检查您是否已在以下位置启用元数据发布 指定的地址。如需帮助启用元数据发布,请 请参阅 MSDN 文档 http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata交流

错误 URI: http://localhost:8732/Design_Time_Addresses/YeagerTechWcfService/YeagerTechWcfService/mex 元数据包含无法解析的引用:

我的 WCF 服务中有以下 OperationContract 代码:

[OperationContract]
        IEnumerable<Category> GetCategories(YeagerTechEntities DbContext);

我的 WCF 服务中有以下 DataContract 代码:

namespace YeagerTechModel
{
    [Serializable]
    [DataContract(IsReference = true)]
    [KnownType(typeof(YeagerTechEntities))]
    public partial class Category
    {
        public Category()
        {
            this.Projects = new HashSet<Project>();
        }

        [DataMember]
        public short CategoryID { get; set; }
        [DataMember]
        public string Description { get; set; }

        [DataMember]
        public virtual ICollection<Project> Projects { get; set; }
    }

}

最后,下面是我的WCF方法:

public IEnumerable<YeagerTechModel.Category> GetCategories(YeagerTechEntities DbContext)
        {
            //YeagerTechEntities DbContext = new YeagerTechEntities();

            DbContext.Configuration.ProxyCreationEnabled = false;

            IEnumerable<YeagerTechModel.Category> category = DbContext.Categories.Where(p => p.CategoryID > 0).AsCached("Categories").ToList();
            //IEnumerable<YeagerTechModel.Category> category = DbContext.Categories.Where(p => p.CategoryID > 0);

            CloseConnection(DbContext);

            return category;
        }

【问题讨论】:

  • 如果您将代码更改为返回null,此错误会消失吗?如果你也摆脱KnownType 怎么样?尝试像这样拆分代码,一次删除一个潜在的故障点,将有助于隔离问题。
  • 在收到我发布的错误后,我将 KnowType 属性放在了我的 DataContract 中。
  • 我认为您不应该在界面中传递上下文。我认为它不会是可序列化的,并且可能会引起巨大的头痛。您是否尝试过移除它(可能在您这样做时让身体变空)?您可以使用其他方法传递它,但应该在服务器端进行选择。
  • 其他方法,例如依赖注入 - stackoverflow.com/questions/3466886/…

标签: wcf entity-framework-4.1


【解决方案1】:

您需要遵循注册表/服务定位器模式的单例对象。该对象将保存对您的全局对象的引用。例如,在应用程序启动时,您将使用SqlDependency 使用您的上下文填充此对象,并且您将使用注册表在控制器的操作和服务的操作中访问此上下文。

无论如何都要非常小心地处理这个问题。 SqlDependency 和 EF 不能很好地结合在一起,因为它会让你的上下文长寿。长寿环境是in most cases anti-pattern。永远不要将该上下文用于其他任何事情,然后加载缓存数据。不要将其用于数据修改或加载非缓存关系!在第一个查询中将实体加载为非跟踪(AsNoTracking 查询扩展方法),并关闭该上下文的代理创建和延迟加载。

还要注意,EF 中的查询始终在数据库中执行。我不确定你的AsCached 应该做什么,但我怀疑它会起作用。你需要的大概是:

var category = DbContext.Categories.Local
                        .Where(p => p.CategoryID > 0)
                        .ToList();

我不会在 EF 中使用 SqlDependency。我会直接使用 ADO.NET 和 SQL。对于 EF 中的缓存,我会检查 EF Caching provider 以使用二级缓存,这在大多数情况下就足够了。

【讨论】:

  • Ladislav,感谢您的 cmets。在阅读了 EF 缓存提供程序之后,似乎这对于我想做的事情来说太复杂了。此外,对某些人来说它有效,而另一些人则无效。我只是等到 EF 在以后的版本中内置了一个缓存属性。我很奇怪,自从 4.0 或 4.1 框架问世以来,为什么 MS 没有想到有这样的东西。希望他们能很快在即将到来的框架中实现这一点。我知道 NHibernate 有一些内置的 SQL 依赖缓存。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多