确保调用api成功并保存自己的成功

时间:2019-01-24 10:11:58

标签: c# asp.net asp.net-mvc entity-framework asp.net-web-api

您好,当我将ASP.NET MVC与EF结合使用并从其他网站(也使用Entity Framework)调用Web API时,发现了问题 问题是

我想确保MVC SaveChanges()和Web API SaveChanges()两者都成功。

这是我梦dream以求的伪代码

public ActionResult Operation()
{
    Code Insert Update Delete....

    bool testMvcSaveSuccess = db.TempSaveChanges();  //it does not have this command.

    if(testMvcSaveSuccess == true)
    {
       bool isApiSuccess = CallApi(); //insert data to Other Web App


       if(isApiSuccess == true)
       {
          db.SaveChanges(); //Real Save
       }
    }
}

根据上述代码,如果没有db.TempSaveChanges(),则Web API可能会成功,但是MVC SaveChanges()可能会失败。

4 个答案:

答案 0 :(得分:2)

因此没有TempSaveChanges之类的东西,因为还有更好的东西: Transactions

交易是一个IDisposable(可以在using块中使用),并且具有诸如 Commit Rollback 的方法。

小例子:

private void TestTransaction()
{
    var context = new MyContext(connectionString);

    using (var transaction = context.Database.BeginTransaction())
    {
        // do CRUD stuff here 

        // here is your 'TempSaveChanges' execution
        int changesCount = context.SaveChanges();

        if (changesCount > 0)
        // changes were made
        {
            // this will do the real db changes
            transaction.Commit();
        }
        else
        {
            // no changes detected -> so do nothing
            // could use 'transaction.Rollback();' since there are no changes, this should not be necessary
            // using block will dispose transaction and with it all changes as well
        }
    }
}

我已从我的GitHub Exercise.EntityFramework存储库中提取了此示例。随意加星/克隆/叉...

答案 1 :(得分:0)

是的。

您需要在上下文类中重载.Savechanges,在该类中将首先调用它,然后在之后调用常规。

或者在上下文类中创建您自己的TempSaveChanges(),然后从中成功调用SaveChanges

答案 2 :(得分:0)

您所指的是 atomicity (原子性):您希望多项操作全部成功或全部都不成功。在数据库的上下文中,您可以通过交易获得此信息(如果数据库支持)。但是,就您而言,您需要一个跨越两个不相交系统的事务。通用的(某些特殊情况下具有更简单的解决方案)这种事务的可靠实现将对两个系统有一定要求,并且还需要额外的持久性。

基本上,您需要能够在序列中的任意时刻从突然停止中正常恢复。您正在使用的每个数据库很可能都符合 ACID ,因此您可以依靠每个数据库事务来满足原子性要求(它们成功或失败)。因此,您只需要担心两个数据库事务的顺序。您对这两个系统的要求是确定后验是否已执行某些操作的一种方法。

示例流程:

  1. 开始运营
  2. 生成唯一的交易ID,并保留(带有请求数据)
  3. 对本地数据库进行更改并提交
  4. 调用外部Web API
  5. 标记交易已完成(或删除)
  6. 操作结束

恢复:

  1. 从商店获取所有待处理(未完成)的交易
  2. 检查是否对本地数据库进行了预期的更改
  3. 如果进行了预期的更改,请询问Web API
  4. 如果未进行任何更改或全部进行了更改,则交易完成:删除/标记它。
  5. 如果进行了一项更改,但未进行另一项更改,则要么还原已进行的更改(还原事务),要么执行未进行的更改(恢复事务)=>然后删除/标记它。

现在,正如您所看到的,它很快变得复杂起来,特别是如果“确定是否进行了更改”不是一件容易的事。常见的解决方案是使用该唯一事务ID作为确定需要注意哪些数据的方式。但是在这一点上,它变得非常特定于应用程序,并且完全取决于特定的操作。对于某些应用程序,您只需在恢复步骤中重新运行整个操作(因为您已将整个请求数据存储在事务中)。某些特殊情况不需要持久化事务,因为还有其他方法可以实现相同的目的,等等。

答案 3 :(得分:0)

好的,让我们澄清一下。

您有一个MVC应用 A1 ,其数据库为 D1 您便有了一个API,我们将其称为 A2 和它自己的数据库 D2

您想要 A1 中的一些代码,该代码会在 D1 中进行临时保存,然后触发对 A2 的调用,如果响应成功然后将 D1 中的温度数据保存在正确的位置。

根据您的伪代码,建议您创建第二个表,将“临时”数据保存在 D1 中。因此您的数据库有一个额外的表,流程如下:

首先将 A1 数据保存在该表中,然后调用 A2 ,数据将保存在 D2 A1 < / strong>收到确认并调用将数据从第二个表移至应有的位置的方法。

要考虑的场景:

  1. 将温度数据保存在 D1 中有效,但对 A2 的调用失败。现在,您可以使用批处理作业清除孤立数据,或仅调用 A2 失败时调用将其删除的数据。

  2. A2 的调用成功,对 D1 的调用失败,所以现在您在 D1 中拥有临时数据,但该数据已失败移动到右边的桌子。您可以在第二行表的每一行添加一个标志,这表明对 A2 的第二次调用已成功完成,因此该数据需要尽可能地移到正确的位置。您可以在此处有一个定期运行的服务,如果它找到标记设置为true的任何数据,则会将数据移到正确的位置。

还有其他方法可以处理这种情况。您可以使用队列系统进行管理。每一行数据都变成一条消息,您为其分配一个唯一的ID,即GUID,它基本上是一个CorrelationID,并且在两个系统中都是相同的。即使一个系统出现故障,恢复运行时,数据也将被保存,并且一切都很好,而且由于具有通用ID,您始终可以正确地将其链接起来。