¿Hay alguna forma de manejar async / await detrás de un servicio ASMX?

Tengo una aplicación web que sirve una API REST WCF para JSON y un servicio web ASMX. La aplicación ha estado presente por algunos años. Está basado en ASP.NET 2.0, pero se actualizó a .NET 4.0 hace un par de años, y acabo de actualizar a .NET 4.5 para poder usar el nuevo marco asíncrono.

Detrás de la aplicación hay algunos servicios legados, y me di cuenta de que hay un gran potencial para boost el rendimiento yendo asincrónico. Implementé asincrónicamente todo el camino a través de la aplicación, y todo está funcionando perfectamente a través de la API WCF REST.

Demasiado tarde descubrí que la API de ASMX falla, quería métodos como este:

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

Luego me enteré de que async / await no es compatible con ASMX, y todos aconsejan migrar a WCF. No estoy muy feliz con esto. Los ASMX (en realidad tres de ellos) están llenos de diferentes métodos, y hay muchos consumidores API que queremos seguir sirviendo desde la anterior API.

¡Pero necesitamos un mayor rendimiento! ¿Alguien sabe acerca de una solución para que pueda seguir usando async / await detrás de ASMX, pero exponer ASMX como antes?

Es posible hacer esto, pero sería un poco incómodo. ASMX admite métodos asíncronos de estilo APM , y puede convertir TAP a APM (sin embargo, tenga en cuenta que el ejemplo de MSDN en esa página no propaga las excepciones correctamente).

Tengo un ejemplo en mi blog que muestra cómo envolver las implementaciones de TAP en APM (con la propagación de excepciones que mantiene el tipo de excepción correcto pero pierde la stack; consulte ExceptionDispatchInfo para una propagación de excepción completamente correcta). Lo usé por un tiempo cuando WCF solo admitía APM. Un enfoque muy similar debería funcionar para ASMX.

Sin embargo, tenga en cuenta que deberá apuntar a 4.5 (es decir, httpRuntime.targetFramework ) para que async / httpRuntime.targetFramework funcione como se espera .

Si su problema es simplemente integrar la parte superior de su lógica asíncrona en su asmx, puede hacer lo mismo que con el siguiente fragmento.

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

Tenga en cuenta que si Trip.GetTrip () arroja una excepción, recibirá una AggregateException, y no la excepción que recibiría si estuviera esperando lanzar la excepción. Tu puedes hacer

 [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(); } }