有没有办法在ASMX服务后面处理async / await?

时间:2013-09-04 19:39:04

标签: c# wcf web-services asynchronous asmx

我有一个Web应用程序,为JSON和ASMX Web服务提供WCF REST API。该应用程序已存在几年。它基于ASP.NET 2.0,但几年前升级到.NET 4.0,我刚刚升级到.NET 4.5以便能够使用新的异步框架。

应用程序背后是一些遗留服务,我意识到通过异步提高性能有很大的潜力。我已经在应用程序中实现了异步,并且一切都通过WCF REST API完美地运行。

太晚了我发现ASMX API失败了,我想要这样的方法:

[WebMethod(Description = "Takes an internal trip ID as parameter.")]
async public Task<Trip> GetTrip(int tripid)
{
    var t = await Trip.GetTrip(tripid);
    return t;
}

然后我了解到ASMX根本不支持async / await,并且每个人都建议迁移到WCF。我对此并不太满意。 ASMX(实际上有三个)填充了不同的方法,并且我们希望从旧的API继续提供大量的API使用者。

但我们需要提高性能!有没有人知道一个解决方法所以我可以继续在ASMX后面使用async / await,但是像以前一样公开ASMX?

3 个答案:

答案 0 :(得分:15)

有可能这样做,但有点尴尬。 ASMX supports APM-style asynchronous methods,您可以convert TAP to APM(但请注意,该页面上的MSDN示例不会正确传播异常)。

我的博客上有一个显示how to wrap TAP implementations in APM的示例(异常传播保留了正确的异常类型但丢失了堆栈;有关完全正确的异常传播,请参阅ExceptionDispatchInfo)。当WCF仅支持APM时,我使用了一段时间。一种非常类似的方法应该适用于ASMX。

但请注意,您将have to target 4.5 (i.e., httpRuntime.targetFramework) for async/await to work as expected

答案 1 :(得分:0)

您可能无法使ASMX服务本身以异步方式运行,但是如果您正在使用javascript从WebApp进行调用,则可以在调用时将服务包装在服务中,以便在客户端中利用异步-侧。

如上所述,它不会使您的服务异步,而是在客户端中以异步方式使用此服务的示例(即,在这种情况下使用javascript promise来停止进一步的操作,直到该服务解决为止。同样,可以对其进行调整以在解决或失败后继续操作并执行其他操作。

优化服务本身只是解决方案的一半,另一半是在客户端内部,因此我认为这对某些扩展很有帮助:)

JavaScript代码:

var tripObj;

async function getTripObject(tripId) {


  // Ensures Trip is fetched before proceeding 
  var promise = new Promise(function (resolve, reject) {
    ASMXService.getTrip(tripId, async function (ret) {
      tripObj = ret;

      resolve("Success");
    }, function () {
      reject("Error");
    });
  });

  await promise;

}

答案 2 :(得分:-1)

如果您的问题只是将异步逻辑的顶部集成到asmx中,则可以执行以下代码段。

[WebMethod(Description = "Takes an internal trip ID as parameter.")] 
public Trip GetTrip(int tripid) {
   var trip = Trip.GetTrip(tripid).Wait();
   return trip; 
}

请注意,如果Trip.GetTrip()抛出异常,您将收到AggregateException,而不是在等待抛出异常时您将收到的异常。你可以做到

[WebMethod(Description = "Takes an internal trip ID as parameter.")] 
public Trip GetTrip(int tripid) {
  try
  {
    var trip = Trip.GetTrip(tripid).Wait();
    return trip; 
  }
  catch(AggregateException ex)
  {
    throw ex.InnerException.First();
  }       
}