【问题标题】:DbContext Injection into WCF ServiceDbContext 注入 WCF 服务
【发布时间】:2014-03-02 01:00:18
【问题描述】:

我想问问你我的想法是否行得通。

我最近开始使用实体框架和 WCF。在我当前的项目中,我希望每个服务都是原子的,也就是说一个服务在一个事务中。但我不想为所有服务操作多次编写相同的事务相关代码。然后我想到了事务及其错误处理在一个地方完成IOperationInvoker 就像下面显示的代码 sn-p 一样。

这个技巧的优点是我可以实例化DbContext 或在使用块中创建事务,这样无论服务中发生什么,它们都会被处理掉。而且我只需要处理一次与数据库相关的异常。

它似乎工作。但我担心这是否是使用 IOperationInvoker 和 EF 的合法方式。

有什么缺点吗?

// service base class
public abstract MyBaseService
{
    DbContext database {get; set;}
}

[ServiceContract]
public interface IMyService {...}

// concrete service class
public class MyService : MyBaseService, IMyService {...}

public class MyOperationInvoker : IOperationInvoker
{
    IOperationInvoker originalOperationInvoker; // to be set at construction

    public object Invoke(object instance, object[] inputs, out object[] outputs)
    {
        using (var dbContext = new MyDbContext())
        {
            // inject DbContext into my service to be used in it.
            (MyServiceBase)instance.database = dbContext;

            // invoke a service within db transaction.
            using (var transaction = dbContext.Database.BeginTransaction())
            {
                try
                {
                    objct ret = originalOperationInvoker.invoke(instance, inputs, outputs);
                    transaction.Commit();
                    return ret;
                }
                catch (Exception e)
                {
                    transaction.Rollback();
                    throw;
                }
            }
        }
    }
    ...
}

【问题讨论】:

  • 我认为codereview 是解决这个问题的更好地方。需要注意的是,IOperationInvoker 的最大缺点是它可以与objects 一起使用。有一些方法可以使其类型更强大,有时称为“中间孔”模式,stackoverflow.com/q/5254881/861716

标签: c# wcf entity-framework


【解决方案1】:

关于使用操作调用程序:是的,您可以这样做。这是在 WCF 中围绕传入调用添加“包装逻辑”的主要位置。请注意,对于异步方法,您需要实现一组不同的接口方法。

关于自动事务管理:我发现隐式事务是不够的,因为你需要控制隔离级别和超时设置。此外,有时您需要多次交易。也许不是在第一个版本中,但最终你会超越这个方案。

我最近成功地创建了一个类,该类将一个 DbContext 和一个事务包装在一个单元中。我的大多数 WCF 方法如下所示:

void SomeMethod() {
 using (var db = new MyDatabaseContext(isolationLevel, timeout, connectionString, ...)) {
  //custom body that uses the wrapped DbContext
  db.CompleteTransaction();
 }
}

这里有一些代码重复,但还不错,我仍然可以完全控制我如何使用数据库。我可以为每个方法使用多个事务、嵌套它们或使用运行时计算的超时值。没有魔法发生(就像隐式调用的操作调用程序)。它也是异常安全的。

【讨论】:

  • out 项目的基本前提之一是每个服务都是原子的。所以,我认为我不需要多次交易。如果我需要另一个事务,例如即使发生异常也记录到记录日志的 DB,我将创建另一个 DbContext 专用于不使用事务的日志记录(这意味着默认的隐式事务)。
  • 好的,有道理。 (虽然我的项目一开始也是同样的假设,后来因为不可预见的原因失效了。)我认为隔离级别是这里最关键的一点。例如,我推荐SNAPSHOT 用于只读事务。这解决了所有并发问题。
【解决方案2】:

另一个想法是拥有一个自定义实例提供程序。实例提供程序允许您通过提供创建和释放实例的显式点来控制 wcf 服务实例的生命周期。

通过将它与 ioc 容器结合使用,您可以将上下文自动注入到服务中,然后在请求完成时释放。

我最近写了一篇博客,请参阅我的博客文章了解技术细节。

http://www.wiktorzychla.com/2014/02/lifetime-management-of-wcf-services.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    • 2011-01-03
    • 1970-01-01
    • 2011-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多