Как поймать все исключения в WCF, но включить пользовательские данные?

Я работаю над проектом, который использует несколько вызовов WCF для выполнения процедуры. Первый вызов возвращает уникальный идентификатор (Guid), который должны предоставить все следующие вызовы. На стороне сервера каждый вызов регистрируется вместе с этим уникальным идентификатором, чтобы можно было наблюдать за ходом одной процедуры (предположим, что клиент может запускать несколько из этих процедур одновременно, и они являются потокобезопасными) < / em>.

Пример на стороне клиента будет примерно таким:

string clientName = GetClientName();
Guid uniqueId = wcfClient.Begin(clientName);
object data = wcfClient.GetData(clientName, uniqueId);

object processedData = ProcessDataLocally(data);

bool success = wcfClient.confirmDataValidity(clientName, uniqueId, processedData);

// ...

wcfClient.End(clientName, uniqueId);

Если что-то пойдет не так на стороне сервера, я бы хотел, чтобы это тоже регистрировалось, используя uniqueId, присвоенный вызову, который пошел не так. С этой целью я использовал все методы службы для использования такой функции:

private T DoProcess<T>(Guid uniqueId, Func<T> process)
{
    try
    {
        return process();
    }
    catch(Exception ex)
    {
        Log(ex, uniqueId);

        throw; // or throw the same thing every time, if the client
               // shouldn't know the details
    }
}

public object GetData(string clientName, Guid uniqueId)
{
    return DoProcess(uniqueId, () =>
    {
        object data;

        // Generate data

        return data;
    });
}

Однако кажется, что это не позволяет выявить все возможные ошибки (например, если время ожидания соединения истекло).

Я читал о реализации интерфейса IErrorHandler и его подключении к службе. Хотя это, кажется, перехватывает все ошибки, похоже, нет другого способа передать ему информацию, кроме исключения, такого как uniqueId. Следовательно, нет возможности зарегистрировать идентификатор.

Можно ли перехватить все исключения и включить данные, которые были переданы методу, в котором возникло исключение?


person George T    schedule 18.08.2016    source источник
comment
stackoverflow.com/questions/3666516/   -  person William Xifaras    schedule 18.08.2016


Ответы (1)


Исключение, такое как Тайм-аут подключения, не поступает в службу, поэтому на стороне службы его невозможно перехватить.

С учетом вышесказанного вы можете использовать IExtension для добавления дополнительной информации к текущему OperationContext. Базовый шаблон для этого примерно такой:

public class OperationContextExtension : IExtension<OperationContext>
{
    private readonly Dictionary<string, object> extraInfo;

    public OperationContextExtension ()
    {
        extraInfo = new Dictionary<string, object>();
    }

    public static OperationContextExtension Current
    {
        get
        {
            OperationContextExtension c = OperationContext.Current.Extensions.Find<OperationContextExtension>();
            if (c == null)
            {
                c = new OperationContextExtension ();
                OperationContext.Current.Extensions.Add(c);
            }
            return c;
        }
    }

    public Dictionary<string, object> Extras
    {
        get { return extraInfo; }
    }

    public void Attach(OperationContext owner) { }

    public void Detach(OperationContext owner) { }
}

А затем используйте этот класс в реализации IErrorHandler:

class FaultErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        return false;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
      Guid ID = OperationContextExtension.Current.Extras["uniqueId"] as Guid;

      LogIt(error.ToString() + ID);
    }
}

А потом в GetData

public object GetData(string clientName, Guid uniqueId)
{
    OperationContextExtension.Current.Extras["uniqueId"] = uniqueId;
    return DoProcess(uniqueId, () =>
    {
        object data;

        // Generate data

        return data;
    });
}
person Serve Laurijssen    schedule 18.08.2016
comment
Current - статическое поле; безопасно ли использовать его, когда одновременно может происходить несколько звонков? - person George T; 30.08.2016
comment
Да, такие внешние значения распространены в WCF. Каждый поток получает другое значение (если у вас настроен PerCall или PerSession) - person Serve Laurijssen; 31.08.2016