Передача Func‹› или аналогичная аспекту PostSharp

В наших внешних границах, которые предоставляют службы WCF, мы преобразуем все внутренние исключения в FaultException. Это ручной процесс, который часто имеет небольшие недостатки, уникальные для каждой реализации. Он был скопирован/вставлен и бездумно изменен (или забыт) для каждого выставленного метода. Чтобы уменьшить количество ошибок, я хотел создать аспект, который перехватывал бы любое необработанное исключение.

Мы делаем сопоставление внутренних исключений с исключениями ошибок. Как я могу отправить функцию сопоставления аспекту?

Если я добавлю свойство к аспекту следующим образом:

[Serializable]
public sealed class FaultExceptionConverter : OnExceptionAspect {
    public Func<Exception, FaultException> FaultConverter { get; set }
}

Я не могу (как и ожидалось из-за ограничений атрибутов) инициализировать его как [FaultExceptionConverter(FaultConverter = MyConversionMethod)] (где MyConversionMethod — это какой-то метод, назначаемый Func<Exception, FaultException>). Есть ли шаблон для передачи этого типа параметра аспекту? Многие типы могут быть переданы в аспекты. Это общая проблема?

Если есть лучший способ сделать это, я был бы признателен за совет.


person carlpett    schedule 12.12.2012    source источник
comment
Я дал ответ на ваш вопрос ниже, но потом подумал - почему сам ваш аспект не реализует требуемую процедуру преобразования? Это, безусловно, упростило бы дело. Если у вас нет нескольких способов создания FaultException из исключения, это на самом деле кажется более подходящим способом сделать это?   -  person RJ Lohan    schedule 13.12.2012
comment
@RJLohan: это предназначено для общего использования. У нас есть более сотни точек интеграции, у каждой из которых есть разные договоры об отказе со своими потребителями, которые, в свою очередь, распределены по 20-30 организациям. Излишне говорить, что было бы сложно создать такую ​​общую процедуру преобразования :)   -  person carlpett    schedule 13.12.2012


Ответы (2)


Я столкнулся с подобными разочаровывающими ограничениями в реализации аспекта, и один из подходов, который я использовал, чтобы обойти их, заключается в том, чтобы аспект рассматривал класс, в котором он реализован, как некоторый тип «поставщика», к которому он может обращаться для запроса других битов. во время выполнения.

Итак, в вашем случае я представляю переопределение OnException, которое выглядит примерно так:

public override void OnException(MethodExecutionArgs args)
{
    IFaultConverterProvider provider = args.Instance as IFaultConverterProvider;
    if (null != provider)
        Func<Exception, FaultException>exceptionConverterFunc = provider.GetFunc();
}

Где IFaultConverterProvider — это некоторый интерфейс, который вы определяете и реализуете для атрибутированного типа, чтобы предоставить дополнительные параметры, которых вам не хватает.

Затем, в качестве небольшой проверки работоспособности, вы можете ввести некоторую проверку времени компиляции в свой аспект, чтобы убедиться, что тип, к которому он применяется, действительно реализует этот требуемый интерфейс;

public override bool CompileTimeValidate(Type type)
{
    if (!type.IsImplementationOf(typeof(IFaultConverterProvider )))
    {
        // The aspect must be in a type which implements IFaultConverterProvider 
        Message.Write(
            MessageLocation.Of(type),
            SeverityType.Error,
            "CUSTOM02",
            "Cannot apply [MyFaultExceptionAspect] to type {0} because it does not implement IFaultConverterProvider .", type);
            return false;
    }

    return true;
}
person RJ Lohan    schedule 12.12.2012
comment
Это довольно умный подход. Единственный недостаток, который я вижу сразу, заключается в том, что пользователь (разработчик службы) захочет предоставить различную логику сопоставления для каждого метода... Я подумаю об этом, поскольку с этим исключением (каламбур не предназначен) он должен решить проблема. - person carlpett; 13.12.2012

К сожалению, вы можете передать в атрибут только bool, byte, char, short, int, long, float, double, string, Type и перечислители.

В качестве обходного пути вы можете передать typeof(FaultConverterClass) как тип и "MyConversionMethod" как строку и вызвать свой метод преобразования с помощью отражения (конечно, только в том случае, если этот метод статичен). Это звучит довольно «грязно», но вы можете добавить проверку времени компиляции на то, что метод существует и имеет ожидаемую подпись.

person Alexander Bortnik    schedule 12.12.2012