Клиент не будет перехватывать универсальное FaultException<T>, только FaultException
Я прочитал все, что есть, чтобы прочитать об этом, но, возможно, я что-то упустил (ну, определенно, я что-то упускаю, иначе это уже сработало бы)
Я выдавал ошибку исключения в бизнес-уровне моего сервера:
public class RfcException : Exception
{
public RfcException(string _m, Exception _inner) : base(_m, _inner)
{ }
public Dictionary<string, string> ExtendedProperties
{
get { return extendedProperties; }
protected set { extendedProperties = value; }
}
private Dictionary<string, string> extendedProperties = new Dictionary<string, string>();
}
который я оставляю необработанным в сервисе, но у меня есть IErrorHandler
поймать и создать FaultMessage
:
public class FaultErrorHandler : BehaviorExtensionElement, IErrorHandler, IServiceBehavior
{
public bool HandleError(Exception error)
{
if (!Logger.IsLoggingEnabled()) return true;
var logEntry = new LogEntry
{
EventId = 100,
Severity = TraceEventType.Error,
Priority = 1,
Title = "WCF Failure",
Message = string.Format("Error occurred: {0}", error)
};
logEntry.Categories.Add("MiddleTier");
Logger.Write(logEntry);
return true;
}
public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
{
if (error is RfcException)
{
RfcException rfcException = error as RfcException;
var serviceFault = new RfcServiceFault(rfcException);
var faultException = new FaultException<RfcServiceFault>(serviceFault, new FaultReason(string.Format("System error occurred, exception: {0}", error)));
var faultMessage = faultException.CreateMessageFault();
fault = Message.CreateMessage(version, faultMessage, Schema.WebServiceStandard);
}
else
{
var faultException = new FaultException<Exception>(error, new FaultReason(string.Format("System error occurred, exception: {0}", error)));
var faultMessage = faultException.CreateMessageFault();
fault = Message.CreateMessage(version, faultMessage, Schema.WebServiceStandard);
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{ }
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher chanDisp in serviceHostBase.ChannelDispatchers)
{
chanDisp.ErrorHandlers.Add(this);
};
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{ }
public override Type BehaviorType
{
get { return typeof(FaultErrorHandler); }
}
protected override object CreateBehavior()
{
return new FaultErrorHandler();
}
}
Не нужно спрашивать; Я уже подтвердил отладчиком его вход в часть if (error is RfcException)
часть, я прошел через этот код, и он дошел до конца без каких-либо проблем. Это errorHandler оборачивает FaultException<RfcServiceFault>
сообщение, RfcServiceFault
сообщение это
[DataContract(Name = "RfcServiceFault", Namespace = "Service.DataTransfer.Rfc")]
public class RfcServiceFault
{
public RfcServiceFault(RfcException rfcException) : this( (Exception)rfcException )
{
ExtendedProperties = new Dictionary<string, string>(rfcException.ExtendedProperties);
}
public RfcServiceFault()
{ }
public RfcServiceFault(Exception regularException)
{
FaultMessage = regularException.Message;
StackTrace = regularException.StackTrace;
}
public Dictionary<string, string> ExtendedProperties
{
get { return extendedProperties; }
protected set { extendedProperties = value; }
}
[DataMember]
private Dictionary<string, string> extendedProperties = new Dictionary<string, string>();
[DataMember]
public string FaultMessage { get; set; }
[DataMember]
public string StackTrace { get; set; }
}
Сервис имеет все аннотации, которые должны иметь сервис wcf с faultContract:
[ServiceContract(Name = "MyService", Namespace = Schema.WebServiceStandard, SessionMode = SessionMode.Allowed)]
public interface IMyService
{
[OperationContract(Name = "GetStuff")]
[FaultContract(typeof(RfcServiceFault) , Name="RfcServiceFault", Namespace="Service.DataTransfer.Rfc")]
LookupResult GetStuff();
}
Теперь: тестирование на клиенте, простой тест вроде этого:
try
{
var result = myService.GetStuff();
Assert.IsTrue(!string.IsNullOrEmpty(result));
}
catch (FaultException<RfcServiceFault> rfcEx)
{
// OMG FOR THE LIFE OF THE PUPPIES ENTER HERE
}
catch (FaultException rr)
{
// it always falls in here
}
catch (Exception ex)
{ }
Я прочитал много, много сообщений об этой аналогичной проблеме:
- Не удается обработать FaultException
- Бросать универсальный FaultException
- C# WCF ловит Fault Исключения Базового типа
- WCF: WSDL-первый подход: проблемы с генерацией типов ошибок
но пока что ничего не помогает, я попытался настроить трассировку WCF в web.config:
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing">
<listeners>
<add name="log"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="c:\Traces.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
и я получаю файл svclog там, я открываю с помощью средства просмотра WCF Trace, но я вижу только кучу сообщений, желтый показывает исключение, но он только подтверждает то, что клиент уже видит, System.ServiceModel.FaultException
получаемый, а не общий
Есть идеи, как это выяснить?
EDIT забыл упомянуть, я включил мой обработчик ошибок в конфигурации, как это:
<behaviorExtensions>
.....
<add name="faultErrorHandlerBehavior"
type="Service.FaultErrorHandler,Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
.....
</behaviorExtensions>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceThrottling maxConcurrentCalls="200" maxConcurrentSessions="200"
maxConcurrentInstances="200" />
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<faultErrorHandlerBehavior />
</behavior>
</serviceBehaviors>
1 ответ
(Это небольшой удар в темноте) Я полагаю, что у вас может быть проблема, потому что действие по ошибке не соответствует ожидаемому на клиенте. Можете ли вы заменить ваш CreateMessage следующим:
fault = Message.CreateMessage(version, faultMessage, faultException.Action);