我尝试让我的WCF服务始终抛出详细的错误,即使没有明确抛出它们也是如此。为实现这一目标,我实施了:
一个ErrorHandler,其IErrorHandler.ProvideFault将非故障错误包装为FaultException
ServiceBehavior扩展,附加此处理程序并向每个操作添加此FaultException的错误描述,因此客户端可能会捕获它。
我使用错误处理程序属性修饰了我的服务(最初我有两个不同的IServiceBehavior实现,用于ErrorHandler和Operation.Faults)。
我还确保新的FaultDescription中的数据集与我在合同中定义FaultContract时检查的数据相同。
无论我尝试什么,当我在合同上使用FaultContract作为属性时,客户端正在正确捕获错误,但是当它在运行时通过ApplyDispatchBehavior附加时,只捕获了一般的FaultException。显然,其他一切(错误包装和抛出)都在工作,只有在运行时向每个操作添加一个FaultContract失败。
请帮忙......
这是代码:
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using Shared.Contracts.Faults;
namespace Server.WcfExtensions
{
public class MyErrorHandler : IErrorHandler
{
#region IErrorHandler Members
public bool HandleError(Exception error)
{
return false;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
if (error is FaultException) return;
if (!error.GetType().IsSerializable) return;
FaultException<GeneralServerFault> faultExc = new FaultException<GeneralServerFault>(new GeneralServerFault(error), new FaultReason("Server Level Error"));
MessageFault messageFault = faultExc.CreateMessageFault();
fault = Message.CreateMessage(version, messageFault, faultExc.Action);
}
#endregion
}
class ErrorHandler : Attribute, IServiceBehavior
{
Type M_ErrorHandlerType;
public Type ErrorHandlerType
{
get { return M_ErrorHandlerType; }
set { M_ErrorHandlerType = value; }
}
#region IServiceBehavior Members
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, ServiceHostBase serviceHostBase)
{
IErrorHandler errorHandler;
try
{
errorHandler = (IErrorHandler)Activator.CreateInstance(ErrorHandlerType);
}
catch (MissingMethodException e)
{
throw new ArgumentException("Must have a public empty constructor.", e);
}
catch (InvalidCastException e)
{
throw new ArgumentException("Must implement IErrorHandler.", e);
}
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
channelDispatcher.ErrorHandlers.Add(errorHandler);
}
foreach (ServiceEndpoint ep in serviceDescription.Endpoints)
{
foreach (OperationDescription opDesc in ep.Contract.Operations)
{
Type t = typeof(GeneralServerFault);
string name = t.Name;
FaultDescription faultDescription = new FaultDescription(ep.Contract.Namespace + "/" + ep.Contract.Name + "/" + opDesc.Name + name + "Fault");
faultDescription.Name = name + "Fault";
faultDescription.Namespace = ep.Contract.Namespace;
faultDescription.DetailType = t;
opDesc.Faults.Add(faultDescription);
}
}
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace Shared.Contracts.Faults
{
[DataContract] //[Serializable]
public class GeneralServerFault
{
[DataMember]
public SerializableException Wrapped
{
get;
private set;
}
public GeneralServerFault()
: base()
{
Wrapped = new SerializableException();
}
public GeneralServerFault(Exception toWrap)
: base()
{
Wrapped = new SerializableException(toWrap);
}
}
[Serializable]
public class SerializableException
{
public string Type { get; set; }
public DateTime TimeStamp { get; set; }
public string Message { get; set; }
public string StackTrace { get; set; }
public SerializableException()
{
this.TimeStamp = DateTime.Now;
}
public SerializableException(string Message)
: this()
{
this.Message = Message;
}
public SerializableException(System.Exception ex)
: this(ex.Message)
{
if (ex == null) return;
Type = ex.GetType().ToString();
this.StackTrace = ex.StackTrace;
}
public override string ToString()
{
return this.Type + " " + this.Message + this.StackTrace;
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.ServiceModel;
using Shared.Contracts.Faults;
namespace Shared
{
internal static class Namespaces
{
internal static class Contracts
{
public const string ServiceContracts = "http://mycompany/services";
}
}
[ServiceContract(Namespace = Namespaces.Contracts.ServiceContracts, SessionMode = SessionMode.Required)]
public interface IContactServices
{
[OperationContract]
[FaultContract(typeof(DataNotFoundFault))]
//[FaultContract(typeof(GeneralServerFault))]
void DoSomething();
}
}
using System;
using System.Collections.Generic;
using System.ServiceModel;
using Shared;
using Shared.Contracts.Faults;
using Server.WcfExtensions;
namespace Server.Services
{
[ErrorHandler(ErrorHandlerType = typeof(MyErrorHandler))]
public class ContactSevices : IContactServices
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public void DoSomething()
{
throw new InvalidCastException("bla");
}
}
}
我省略了客户端和主机的代码