【问题标题】:How to avoid duplicate "using" code如何避免重复的“使用”代码
【发布时间】:2017-07-07 10:50:05
【问题描述】:

我有一个 wcf api 并希望将所有请求包装在一个事务中

目前我的代码在每个端点中都是这样的

public MyCompleteList ReadOrganisations()
    {
        MyCompleteList resp = new MyCompleteList ();
        try
        {
            using (TransactionScope scope = new TransactionScope())
            {
                if (HttpContext.Current.User.Identity.IsAuthenticated)
                {
                    DC_Base browser_request = new DC_Base(PROJECT);
                    browser_request.cmd_user_id = coreDb.GetUserIDFromLoginName(PROJECT,
                        HttpContext.Current.User.Identity.Name);
                    resp =
                        new MyCompleteList (coreSc.User_Read_All_Organisations(browser_request, utils,
                            validation, coreSc, coreDb));
                    scope.Complete();
                }
                else
                {
                    resp.SetResponseNotLoggedIn();
                }

            }
        }
        catch (TransactionAbortedException ex)
        {
            resp.SetResponseServerError();
        }
        catch (ApplicationException ex)
        {
            resp.SetResponseServerError();
        }
        return resp;
    }

如您所见,如果我要在每个端点(大约 300 个)中使用“使用”事务范围部分,这将是很多重复的代码。

有没有办法减少重复的数量?

【问题讨论】:

  • 是的,创建一个父类,把你的代码移进去。
  • 你是什么意思?您能否提供更多详细信息,目前此 wcf 服务从接口继承到基类,然后再到顶级类添加父类是什么意思?这些函数由外部客户端调用,也就是通过 json
  • 你的问题不是很清楚——“使用”是如何导致代码重复的?
  • 如果我想在来自客户端的每个端点调用中使用一个事务,那么我需要在每个重复的端点中使用 (....) 示例只是其中之一我们的 api 提供的许多端点
  • 另外,请不要对 SQL Server 使用 SERIALIZABLE 事务。将 TransactionScope 更改为 READ COMMITTED。见blogs.msdn.microsoft.com/dbrowne/2010/06/03/…

标签: c# sql sql-server wcf transactions


【解决方案1】:

您可以编写一个辅助方法,在将实际代码调用为 lambda 时处理事务逻辑。

    public static T Execute<T>(Func<T> func, TransactionExecutionOptions options = null)
    {
        options = options ?? TransactionExecutionOptions.Default;

        T res;
        using (var tx = new TransactionScope(options))
        {
            res = func();
            tx.Complete();
        }

        return res;
    }

根据您的需要,您可以为Func 参数提供其他参数;例如,Execute 方法还可以打开数据库连接并将其传递给 func(然后将 Func&lt;IDbConnection, T&gt; 作为参数类型)。 YMMV。

你的例子:

public MyCompleteList ReadOrganisations()
{
    MyCompleteList resp = new MyCompleteList ();
    try
    {
        resp = Execute(() => {
            if (HttpContext.Current.User.Identity.IsAuthenticated)
            {
                DC_Base browser_request = new DC_Base(PROJECT);
                browser_request.cmd_user_id = coreDb.GetUserIDFromLoginName(PROJECT,
                    HttpContext.Current.User.Identity.Name);
                resp =
                    new MyCompleteList (coreSc.User_Read_All_Organisations(browser_request, utils,
                        validation, coreSc, coreDb));
                scope.Complete();
            }
            else
            {
                resp.SetResponseNotLoggedIn();
            }
       });
    }
    catch (TransactionAbortedException ex)
    {
        resp.SetResponseServerError();
    }
    catch (ApplicationException ex)
    {
        resp.SetResponseServerError();
    }
    return resp;
}

如果可能,您还可以将SetResponse*() 方法分解到基类或接口中(比如IMyResponse),这样就可以在Execute 方法中处理这方面的问题。

    public static T Execute<T>(Func<T> func, TransactionExecutionOptions options = null) where T : IMyResponse
    {
        options = options ?? TransactionExecutionOptions.Default;

        T res;
        try
        {
            using (var tx = new TransactionScope(options))
            {
                res = func();
                tx.Complete();
            }
        }
        catch (TransactionAbortedException ex)
        {
            res.SetResponseServerError();
        }
        catch (ApplicationException ex)
        {
            res.SetResponseServerError();
        }
        return res;
    }

【讨论】:

  • 好的,这看起来像我在想的我可以给它一个测试谢谢你的回答。
  • 是的,我在接口中已经有了响应,所有响应都从这些接口继承,所以看起来更好
【解决方案2】:

1- 创建一个ServiceBase类如下

public class ServiceBase
    {

       protected void ExecuteOperation(Action codetoExecute)
        {                               
            try
            {               
                 using (TransactionScope scope = new TransactionScope())
                {                   
                    codetoExecute.Invoke();             
                    scope.Complete();                
                }                           
            }
            catch (TransactionAbortedException ex)
            {
                // handle exception
            }
            catch (ApplicationException ex)
            {
                // handle exception
            }            
        }
    }

2- 每个新服务都必须继承自 ServiceBase 并改为调用 ExecuteOperation。代码如下:

ExecuteOperation(() =>
            {                 
                 // Custom code here
            });

3- 原子事务在执行不期望返回结果的操作时很有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    • 2021-06-20
    • 2018-08-16
    • 1970-01-01
    • 2014-03-07
    相关资源
    最近更新 更多