我想问你我的想法是否会运作良好。
我最近开始使用Entity Framework和WCF。在我当前的项目中,我希望每个服务都是原子的,也就是说一个服务在一个事务中。但我不想为所有服务操作多次编写相同的事务相关代码。然后我认为交易及其错误处理是在一个地方IOperationInvoker
完成的,就像下面显示的代码片段一样。
这个技巧的优点是我可以实例化DbContext
或使用块创建事务,这样它们肯定可以处理服务中发生的任何事情。我只需处理一次与db相关的异常。
似乎有效。但我担心这是否是使用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;
}
}
}
}
...
}
答案 0 :(得分:2)
使用操作调用程序时:是的,您可以执行此操作。这是在WCF中为传入呼叫添加“包装逻辑”的主要场所。请注意,对于异步方法,您需要实现一组不同的接口方法。
关于自动事务管理:我发现隐式事务不足,因为您需要控制隔离级别和超时设置。此外,有时您需要多个交易。也许不是在第一个版本,但最终你会超过这个计划。
我最近成功做的是在一个单元中创建一个类包装 DbContext和一个事务。我的大多数WCF方法都是这样的:
void SomeMethod() {
using (var db = new MyDatabaseContext(isolationLevel, timeout, connectionString, ...)) {
//custom body that uses the wrapped DbContext
db.CompleteTransaction();
}
}
这里有一些代码重复,但它并不太糟糕,我仍然可以完全控制我如何使用数据库。我可以为每个方法使用多个事务,嵌套它们或使用运行时计算的超时值。没有什么神奇的东西(就像一个隐含的操作调用者)。它也是例外安全。
答案 1 :(得分:2)
另一个想法是拥有一个自定义实例提供程序。实例提供程序允许您通过提供创建和释放实例的显式点来控制wcf服务实例的生存期。
通过将其与ioc容器相结合,您可以将上下文自动注入服务,然后在请求完成时处理。
我最近在博客上发表了这篇文章,请参阅我的博客文章了解技术细节。
http://www.wiktorzychla.com/2014/02/lifetime-management-of-wcf-services.html