我已经阅读了所有关于这一点的内容,但也许我错过了一些东西(好吧,我肯定错过了一些东西,否则它会有效)
我在服务器业务层中抛出了一些异常错误:
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>();
}
Run Code Online (Sandbox Code Playgroud)
我在服务中留下未经处理的,但我有一个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 …Run Code Online (Sandbox Code Playgroud) 我试图在WCF客户端上捕获给定的FaultException.我基本上需要从fault类中提取内部描述,然后我可以将它打包到另一个异常中,以便上层执行任何操作.
我已经成功完成了很多次,这次使它与众不同的是故障被声明为一个数组,正如您在抛出异常的方法之上声明的服务引用属性所看到的那样:
[System.ServiceModel.FaultContractAttribute(typeof(FaultClass[]), Action = "http://whatever/", Name = "whateverBusinessFault")]
Run Code Online (Sandbox Code Playgroud)
这是我的代码:
try
{
// call service here
}
catch (FaultException<FaultClass[]> ex)
{
if (ex.Detail != null && ex.Detail.Length > 0)
{
throw new CustomException(ex.Detail[0].description);
}
else
{
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
问题是细节(这是一个数组)总是在代码中变回空,即使我可以在WCF跟踪的SOAP响应中看到数据(描述字段等).
所以我需要的东西肯定会回来,但由于某种原因要么它没有被反序列化,要么我无法从代码中获得它.
任何帮助赞赏!
更新:
尝试@Darin建议但没有运气,我从XmlReader中提取的字符串是"/ r/n":
var sb = new StringBuilder();
using (XmlReader reader = fault.GetReaderAtDetailContents())
{
while (reader.Read())
sb.AppendLine(reader.ReadOuterXml());
}
var detail = sb.ToString();
Run Code Online (Sandbox Code Playgroud)
看起来细节部分根本没有出现!
从WCF服务单元测试预期故障的最佳方法是什么?
我正在尝试对WCF服务进行单元测试,该服务(正确地)抛出FaultExceptions以获得某个可重现的错误.单元测试获取WCF客户端的实例并调用适用的服务方法,该方法抛出FaultException.
所有这些都可以按照您的预期运行,但是我对单元测试很困难,因为当服务实现中没有捕获到错误时,错误会导致IDE崩溃.因为我使用的是故障而不是异常,所以我希望IDE能够序列化异常并将其发送到客户端,在那里它会引发异常.
我确实看到有一个配置选项来禁用特定用户未处理异常的中断,但我希望有人能指出一种更好的方法来实现相同的结果,因为这在团队环境中不容易实现.
下面是一些示例代码,介绍了当前实现的内容......
单元测试项目有一个对我的WCF服务的服务引用,我已经定义了这样的接口:
[OperationContract(Name = "DoSomething")]
[FaultContract(typeof(EpicFail))]
ResponseObject DoSomething(RequestObject requestObject);
Run Code Online (Sandbox Code Playgroud)
故障定义如下:
[DataContract]
public class EpicFail
{
public EpicFail(string action)
{
this.Reason = "Epic Fail";
this.Action = action;
}
[DataMember]
public string Reason
{
get;
set;
}
[DataMember]
public string Action
{
get;
set;
}
}
Run Code Online (Sandbox Code Playgroud)
调用该服务的代码看起来像这样:
[TestMethod()]
[ExpectedException(typeof(FaultException<EpicFail>))]
public void FaultTest_Fails_Epicly()
{
bool testPassed = false;
try
{
ResponseObject resp = GetServiceClient().DoSomething(req);
}
catch (FaultException<EpicFail>)
{
testPassed = true;
}
Assert.IsTrue(testPassed);
}
Run Code Online (Sandbox Code Playgroud)
我知道WCF会将异常转换为错误并将其作为SOAP消息发回,但我想知道这是否真的可以互操作.我想我正在努力找出这种可能的情况:
我想我只是很难理解它是如何仍然可以互操作的,因为它期望Java知道如何转换.NET编译的UnisonAccessException的SOAP错误.
我有一些预定义FaultContract属性的WCF服务.当FaultException<TDetail>抛出异常,他们会派堆栈跟踪,源代码和其他可能取消保存信息.
是否有可能仅返回:
我创建了一个在IIS和wcf客户端托管的简单wcf服务,并发现当你从wcf服务捕获一个FaultException,然后调用client.Abort()来释放会话(如微软样本所说)它不会发布会话并在第11次电话会议中挂断.
这是一个例子:
Wcf服务:
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
public class Service1 : IService1
{
public string GetData(int value)
{
throw new FaultException("Exception is here");
return string.Format("You entered: {0}", value);
}
}
Run Code Online (Sandbox Code Playgroud)
客户:
class Program
{
static void Main(string[] args)
{
Service1Client client = null;
for(int i = 0; i < 15; i++)
{
try
{
client = new Service1Client();
client.GetData(100);
}
catch (TimeoutException timeoutEx)
{
Console.WriteLine(timeoutEx);
client.Abort();
}
catch (FaultException faultEx)
{
Console.WriteLine(faultEx);
client.Abort();
} …Run Code Online (Sandbox Code Playgroud) 什么更有效率?抛出异常或抛出错误......我看到的方式是有两种情况:
发生异常并被捕获,您是否抛出现有的Exception或创建一个新的FaultException并抛出它?
您自己的逻辑(例如用户名不能为空)需要将错误抛出为Exception或FaultException.你选哪个?
基本上,哪种方式是最佳实践方式?我问,因为我记得在某处读到有关WCF装箱或拆箱的异常,并且它需要花费额外的资源等...所以我猜也是,这是更有效的方式?
我目前正在使用WCF后端处理WPF应用程序.我们已经实现了客户端日志记录解决方案和用于异常处理的服务器日志记录解决方案,并且它们运行良好,但通常很难通过网络将信息绑定在一起.如果在服务器上发生异常,我想要一种方法将异常令牌传回到线路,以便我可以在客户端上将其记录,但异常.这样,当我在解决客户端错误时遇到问题时,我可以很容易地将其与服务器异常相关联.
我想提供一些关于我们架构的更多信息,然后我会陈述我的问题.
我们的WCF实现比设置服务引用的开箱即用方法更强大.我们在客户端上实现了动态代理生成.我们通过创建客户端和服务器共享的Web服务接口来完成此任务,并使用Castle.DynamicProxy.ProxyGenerator类和CreateInterfaceProxyWithoutTarget方法来创建代理.另外,当我们调用CreateInterfaceProxyWithoutTarget方法时,我们指定一个IInterceptor实现.在服务器上有三个主要类,用于跟踪和故障行为:
FaultOperationInvoker(Implements IOperationInvoker):尝试使用IOperationInvoker.Invoke调用服务方法.如果是故障异常类型,则重新抛出,如果是异常,则尝试确定是否存在具有特定详细信息类型的故障合同,如果是,则进行换行,然后使用详细信息引发新的故障异常.
internal class FaultOperationInvoker : IOperationInvoker
{
IOperationInvoker innerOperationInvoker;
FaultDescription[] faults;
public FaultOperationInvoker(IOperationInvoker invoker, FaultDescription[] faults)
{
this.innerOperationInvoker = invoker;
this.faults = faults;
}
#region IOperationInvoker Members
object[] IOperationInvoker.AllocateInputs()
{
return this.innerOperationInvoker.AllocateInputs();
}
object IOperationInvoker.Invoke(object instance, object[] inputs, out object[] outputs)
{
try
{
return this.innerOperationInvoker.Invoke(instance, inputs, out outputs);
}
catch (FaultException e)
{
ServerLogger.GetLogger(instance.GetType().FullName).LogException(e, "Unhandled exception in service operation.");
//allow fault exceptions to bubble out
throw;
}
catch (Exception e)
{
Type exceptionType = e.GetType(); …Run Code Online (Sandbox Code Playgroud) 我试图在我的WCF服务的FaultException中抛出自己的自定义异常,并在我的WCF客户端中捕获它.但是,在客户端,异常将作为非泛型FaultException捕获,并且我的自定义异常的详细信息将丢失.
我的自定义例外是:
[Serializable] public class MyCustomException : ApplicationException
{ ... }
Run Code Online (Sandbox Code Playgroud)
这是我扔它的方式:
throw new FaultException<MyCustomException>(new MyCustomException("foo bar!"));
Run Code Online (Sandbox Code Playgroud)
(请注意,我在接口中的方法上放置了[FaultContract(typeof(MyCustomException))]
以下是我尝试在客户端捕获它的方法:
...
catch (FaultException<MyCustomException> mcex)
{
Console.WriteLine(mcex);
}
catch (FaultException fex)
{
Console.WriteLine(fex);
}
Run Code Online (Sandbox Code Playgroud)
我的目标是在上面的第一个catch子句中捕获异常,但最终会在第二个catch子句中捕获.
奇怪的是,如果我用ApplicationException替换MyCustomException,那么确实正确捕获了FaultException.
我猜测问题是MyCustomException序列化为Serializable(而不是通过DataContractSerializer),也许我错过了一些WCF的附加指令.ServiceKnownType属性中的某些内容?(虽然我尝试过,但无济于事).
我在调用时从WCF服务收到FaultException,如下所示:
2012-04-02 16:26:00.3593|Error|System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: The type initializer for 'vService.CheckService' threw an exception. (Fault Detail is equal to An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is:
System.TypeInitializationException: The type initializer for 'vService.CheckService' threw an exception. ----> System.NullReferenceException: Object reference not set to an instance of an object.
at vService.CheckService..cctor() in d:\working\code\VioletServer\vService\CheckService.cs:line 14
--- End of inner ExceptionDetail stack trace ---
at vService.CheckService..ctor()
at CreatevService.CheckService()
at System.ServiceModel.Dispatcher.InstanceProvider.GetInstance(InstanceContext instanceContext, Message message)
at System.ServiceModel.Dispatcher.InstanceBehavior.GetInstance(InstanceContext instanceContext, Message request)
at System.ServiceModel.InstanceContext.GetServiceInstance(Message message)
at System.ServiceModel.Dispatcher.InstanceBehavior.EnsureServiceInstance(MessageRpc& rpc)
at …Run Code Online (Sandbox Code Playgroud) faultexception ×10
wcf ×10
c# ×4
exception ×2
fault ×2
.net ×1
castle ×1
soapfault ×1
stack-trace ×1
unit-testing ×1
wcf-faults ×1