Если у стороннего API есть механизм отмены, используйте его.
lock(typeof MyWebServiceClass)
{
if (ThirdPartyApiThatAcceptsTimeout(TimeSpan.FromMinutes(5)))
{
// The call was successful so proceed.
}
else
{
// The call timed out so bail out.
return;
}
}
Однако я очень подозреваю, что у этого API нет механизма отмены, и именно поэтому вы задали этот вопрос. Если это так, то это стало экспоненциально сложнее.
Наивным подходом было бы отложить вызов API другому потоку. Если поток не отвечает своевременно, вы можете прервать его.
lock(typeof MyWebServiceClass)
{
var thread = new Thread(
() =>
{
ThirdPartyApiThatCouldBlockIndefinitely();
});
thread.Start();
if (thread.Join(TimeSpan.FromMinutes(5))
{
// The call was successful so proceed.
}
else
{
// The call timed out so bail out.
thread.Abort();
return;
}
}
Хотя с этим много проблем. Во-первых, нет никакой гарантии, что поток примет запрос на прерывание. Начиная с 2.0 в CLR есть специальные правила, которые определяют, когда прерывания могут быть введены в поток. Я считаю, что CLR будет откладывать внедрение, пока выполняется неуправляемый код. Так что если ваш API неуправляемый, то прерывание может не работать. Кроме того, прерывания являются добровольными, поскольку поток может перехватить ThreadAbortException
и игнорировать его. Во-вторых, прерывание опасно, поскольку прерывание может быть введено асинхронно. Это очень затрудняет защиту от повреждения общего состояния. Вот почему AppDomain обычно завершается после прерывания.
Самый безопасный способ справиться с этим - поместить вызов API в отдельный процесс. Вы должны будете использовать протоколы межпроцессного взаимодействия, такие как .NET Remoting, WCF, каналы и т. Д. Для передачи данных в / из вызова, что будет очень трудно поддерживать. Но это будет самым безопасным, поскольку вы можете безопасно завершить процесс без риска повреждения AppDomain вызывающей стороны.
Я действительно чувствую к вам, потому что эту проблему действительно трудно решить правильно.