I am testing WCF for potentially implementing an API for remote controlling a device that runs our Controller-Software (C#/.Net 4.6.1) on Windows.
I am currently trying to figure out how to throw and catch a FaultException from my service and catch it from a .Net client.
The problem I am having is that when running the code (in Debug-mode on VS 2015), the exception is not caught by the client, but VS ends up showing me the exception inside VS at the code-location of the service (Service.cs), where it is being thrown. The exception message is:
An exception of type 'System.ServiceModel.FaultException`1' occurred in WcfService.dll but was not handled in user code
Additional information: The argument value was not 1
where The argument value was not 1 is the custom message provide by me. Here are the relevant parts of my code. I hope somebody can spot, what I am doing wrong:
IService.cs:
[ServiceContract(CallbackContract = typeof(IMyEvents))]
public interface IService
{
[OperationContract]
[FaultContract(typeof(InvalidValueFault))]
string ThrowsFaultIfArgumentValueIsNotOne(int value);
...
}
[DataContract]
public class InvalidValueFault
{
private string _message;
public InvalidValueFault(string message)
{
_message = message;
}
[DataMember]
public string Message { get { return _message; } set { _message = value; } }
}
Service.cs:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant,
InstanceContextMode = InstanceContextMode.Single)]
public class Service : IService
{
private string defaultString;
public Service(string ctorTestValue)
{
this.defaultString = ctorTestValue;
}
public string ThrowsFaultIfArgumentValueIsNotOne(int value)
{
if (value == 1)
return string.Format("Passed value was correct: {0}", value);
// this is where the box with the exception is shown inside Visual Studio
throw new FaultException<InvalidValueFault>(new InvalidValueFault("The argument value was not 1"), new FaultReason("The argument value was not 1"));
}
...
}
Server.cs:
public class Server
{
private ServiceHost svh;
private Service service;
public Server()
{
service = new Service("A fixed ctor test value that the service should return.");
svh = new ServiceHost(service);
}
public void Open(string ipAdress, string port)
{
svh.AddServiceEndpoint(
typeof(IService),
new NetTcpBinding(),
"net.tcp://"+ ipAdress + ":" + port);
svh.Open();
}
public void Close()
{
svh.Close();
}
}
Client.cs:
public class Client : IMyEvents
{
ChannelFactory<IService> scf;
IService s;
public void OpenConnection(string ipAddress, string port)
{
var binding = new NetTcpBinding();
scf = new DuplexChannelFactory<IService>(
new InstanceContext(this),
binding,
"net.tcp://" + ipAddress + ":" + port);
s = scf.CreateChannel();
}
public void CloseConnection()
{
scf.Close();
}
public string ThrowsFaultIfArgumentValueIsNotOne(int value)
{
try
{
return s.ThrowsFaultIfArgumentValueIsNotOne(value);
}
catch (System.ServiceModel.FaultException<InvalidValueFault> fault)
{
Console.WriteLine("Exception thrown by ThrowsFaultIfArgumentValueIsNotOne(2):");
Console.WriteLine("Exception message: " + fault.Message);
//throw;
return "Exception happend.";
}
}
...
}
Program.cs (Test Program using the server and the client):
class Program
{
static void Main(string[] args)
{
// start server
var server = new Server();
server.Open("localhost", "6700");
Console.WriteLine("Server started.");
var client = new Client();
client.OpenConnection("localhost", "6700");
Console.ReadLine();
Console.WriteLine("Result for client.ThrowsFaultIfArgumentValueIsNotOne(1): {0}", client.ThrowsFaultIfArgumentValueIsNotOne(1));
Console.ReadLine();
Console.WriteLine("Result for client.ThrowsFaultIfArgumentValueIsNotOne(2): {0}", client.ThrowsFaultIfArgumentValueIsNotOne(2));
Console.ReadLine();
client.CloseConnection();
Thread.Sleep(1000);
server.Close();
}
}
If you generated your SOAP code from wsdl using vs tools then FaultException that is being thrown here is generic FaultException - meaning it is FaultException<fault_contract>. You what generic type exception that is by checking your service reference code and inspecting [System.ServiceModel.FaultContractAttribute()] attribute. This attribute has Type parameter which is you generic type.
So if you it looks something like this
[System.ServiceModel.FaultContractAttribute(typeof(MyFaultContract)]
[System.ServiceModel.OperationContractAttribute(Action = "SoapAction", ReplyAction = "*")]
SoapResponse SoapAction(SoapRequest request);
then your catch clause should look like this
try {
soapClient.SoapAction(new SoapRequest());
}
catch (FaultException<MyFaultContract> e) {
}
I had his issue recently (if i understood correctly)
1) VS -> DEBUG -> Options and Settings -> Debugging -> General
There UNTICK 'Break when exceptions cross AppDomain...'
2) DEBUG -> Exceptions and deselect the exceptions for common language runtime (both Thrown and user-unhandled) and try it again. If that solves the problem, you can seek which exception(s) you want to customize or just do this whenever testing exceptions across the AppDomain.
Ok. I found the answer to my question by luck. The error was due to running my code in Debug mode in Visual Studio, where VS catches the exception the moment it is thrown. In order for it to work correctly you need to disable some settings. To do this go to Tools->Option->Debugging->General and remove the checkmarks:
Enable the exception assistant
Enable just my code
I found this solution here.
Related
I am developing a Xamarin APP where I want to call the Web Service
I don't get any Result from the Web Service but the following Exception:
"An exception occurred during the operation, making the result invalid. Check InnerException for exception details."
I've seen a lot of YouTube Vedio and surfed the Internet for a long time, but I haven't found a solution.
This is my Web Service:
//web Service from ASMX project
public class WStest : System.Web.Services.WebService {
[WebMethod(MessageName = "Test", Description = "test")]
[System.Xml.Serialization.XmlInclude(typeof(Result))]
public Result test() {
Result result = new Result();
result.msg = "test successful";
result.flag = 1;
result.userNum = "usernummer";
return result;
}
}
this is just a part of Xammrain Code
private void Butsend_Click(object sender, EventArgs e) {
WStest.WStest test = new WStest.WStest();
test.testCompleted += Test_testCompleted;
test.testAsync(); //call Web Service
//throw new NotImplementedException();
}
private void Test_testCompleted(object sender, WStest.testCompletedEventArgs e)
{
try
{
var a = e.Result.msg;
}
catch(Exception ex)
{
Console.WriteLine(ex.Message); //here I get the exception
}
}
and thanks for all Answers
You are throwing a bid again NotImplementedException (); at the end of the method, you can only comment :)
My intention is to detect unhandled errors inside a WCF service, log them and shutdown the application.
For this purpose I use WCF's IErrorHandler. In the method HandleError(Exception error) I am notified that an exception occured. Everything works ok. At the end of the question you will find complete listing. Here is the output:
00000: Starting service ...
00041: Client call ThrowUnexpected
00056: Service is throwing [InvalidOperationException]
00063: Client chatched [FaultException]
10070: ErrorHandler got [TimeoutException]
10070: ErrorHandler got [InvalidOperationException]
There are two things I am unhappy about:
Instead of expected InvalidOperationException I first get TimeoutException and then the one I have thrown. If I would log and shutdown after the first one I will have wrong information in my log.
The callback does not arrive immediately, only after about 10 seconds. These seems to be exactly those timeout seconds which are probably default for net.tcp. It is too late for me because I wont to terminate the process immediately after something unexpected happened.
Question 1: Is it a bug or is it normal that I get my exception only on second place? Can I assume that for any WCF configuration I will get this pair of exceptions? Is there any way to get only the exception which was thrown inside the method?
Question 2: Is there any way to be called immediately and not after timeout?
Listing:
internal class Program
{
private static void Main(string[] args)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
Console.WriteLine("{0:00000}: Starting service ...", stopwatch.ElapsedMilliseconds);
var instance = new SomeService(stopwatch);
var uri = new UriBuilder(Uri.UriSchemeNetTcp, IPAddress.Loopback.ToString(), 8085, "SomeService").Uri;
using (var host = new ServiceHost(instance))
{
host.AddServiceEndpoint(typeof (ISomeService), new NetTcpBinding(), uri);
host.Description.Behaviors.Add(new ErrorHandlerBehavior(new ErrorHandler(stopwatch)));
host.Open();
// DO NOT DISPOSE Channel is broken
var proxy = new SomeServiceProxy(uri);
{
try
{
Console.WriteLine("{0:00000}: Client call ThrowUnexpected", stopwatch.ElapsedMilliseconds);
proxy.ThrowUnexpected();
}
catch (FaultException ex)
{
Console.WriteLine("{0:00000}: Client chatched [{1}]", stopwatch.ElapsedMilliseconds,
ex.GetType().Name);
}
}
}
}
}
}
[ServiceContract]
public interface ISomeService
{
[OperationContract]
void ThrowUnexpected();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class SomeService : ISomeService
{
private readonly Stopwatch _stopwatch;
public SomeService(Stopwatch stopwatch)
{
_stopwatch = stopwatch;
}
public void ThrowUnexpected()
{
var exception = new InvalidOperationException();
Console.WriteLine("{0:00000}: Service is throwing [{1}]", _stopwatch.ElapsedMilliseconds,
exception.GetType().Name);
throw exception;
}
}
public class ErrorHandler : IErrorHandler
{
private readonly Stopwatch _stopwatch;
public ErrorHandler(Stopwatch stopwatch)
{
_stopwatch = stopwatch;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
}
public bool HandleError(Exception error)
{
Console.WriteLine("{0:00000}: ErrorHandler got [{1}]", _stopwatch.ElapsedMilliseconds, error.GetType().Name);
return false;
}
}
public class SomeServiceProxy : ClientBase<ISomeService>, ISomeService
{
public SomeServiceProxy(Uri uri)
: base(new NetTcpBinding(), new EndpointAddress(uri))
{
}
public void ThrowUnexpected()
{
Channel.ThrowUnexpected();
}
}
public class ErrorHandlerBehavior : IServiceBehavior
{
private readonly IErrorHandler m_Handler;
public ErrorHandlerBehavior(IErrorHandler errorHandler)
{
m_Handler = errorHandler;
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
var dispatcher = (ChannelDispatcher) channelDispatcherBase;
dispatcher.ErrorHandlers.Add(m_Handler);
}
}
}
I think you have a small misunderstanding how the IErrorHandler works. I refer to the MSDN. First comes the ProvideFault method
All ProvideFault implementations are called first, prior to sending a response message. When all ProvideFault implementations have been called and return, and if fault is non-null, it is sent back to the client according to the operation contract. If fault is null after all implementations have been called, the response message is controlled by the ServiceBehaviorAttribute.IncludeExceptionDetailInFaults property value.
then comes the HandleError method
Because the HandleError method can be called from many different places there are no guarantees made about which thread the method is called on. Do not depend on HandleError method being called on the operation thread.
The TimeoutException you are seeing comes from the closing of the ServiceHost (end of the using-Block). You can control this by setting the CloseTimeout on the ServiceHost.
host.CloseTimeout = TimeSpan.FromSeconds(2);
Why does the Timeout happend at all?
This is because, the connection from the proxy to the service is still there and not closed, even when the proxy is in the faulted state. To resolve this you need to call Abort in the catch-block of the FaultedException.
catch (FaultException ex)
{
proxy.Abort();
Console.WriteLine("{0:00000}: Client chatched [{1}]", stopwatch.ElapsedMilliseconds,
ex.GetType().Name);
}
This will result in the following output
00000: Starting service ...
00005: Client call ThrowUnexpected
00010: Service is throwing [InvalidOperationException]
00014: Client chatched [FaultException]
00026: ErrorHandler got [CommunicationException]
00029: ErrorHandler got [InvalidOperationException]
So my service is a simple chat application between two wcf clients. Event callback works when I call events. After I close my client and run it again, and write a message again (to call the event) it throws me exception:
An exception of type 'System.ObjectDisposedException' occurred in
RussianRouletteServiceLibrary.dll but was not handled in user code
Additional information: Cannot access a disposed object.
The code for my service callback is as follows:
private static Action<User, UMessage> gameChat = delegate { };
public void Play()
{
IGameCallback subscriber =
OperationContext.Current.GetCallbackChannel<IGameCallback>();
gameChat += subscriber.PlayerSentMessage;
}
This is the event trigger:
public void SendMessage(User user, UMessage message)
{
try
{
gameChat(user, message);
}
catch (Exception ex)
{
throw ex;
}
}
I get this error every time I .ChannelFactory.Close(); .Close(); the client while closing form event is happening.
Is there anyone that knows how to fix this and is willing to share his knowledge?
Thank you in advance!
EDIT #1
This is the code of the client when it opens:
ConcurrencyMode.Multiple,
UseSynchronizationContext = false)]
public partial class GameForm : Form, IGameCallback
{
#region IGame Callbacks
public void PlayerSentMessage(User user, UMessage message)
{
string nickname = user.NickName == clientUser.NickName ? "You" : user.NickName;
this.Invoke(new MethodInvoker(() => lb_ChatBox.Items.Add(nickname + " : " + message.MessageContent)));
}
#endregion
private GameClient _gameClient = null;
private InstanceContext _instance = null;
private User clientUser = new User(){ Email = "zigm4s#gmail.com", Id = 0, FirstName = "Zigmas", LastName = "Slusnys", NickName = "Ziggy", Password = "test123"};
public GameForm()
{
string state;
if (_gameClient != null)
{
MessageBox.Show("nelygu null");
MessageBox.Show(_gameClient.State.ToString());
//_gameClient = new GameClient(new InstanceContext(this));
}
else
{
_gameClient = new GameClient(new InstanceContext(this));
MessageBox.Show(_gameClient.State.ToString());
}
InitializeComponent();
try
{
_gameClient.Open();
_gameClient.Play();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
This is when the client form is closing.
private void GameForm_FormClosing(object sender, FormClosingEventArgs e)
{
try {
if (_gameClient.State != System.ServiceModel.CommunicationState.Faulted)
{
MessageBox.Show("Closing client");
_gameClient.ChannelFactory.Close();
_gameClient.Close();
}
else
{
MessageBox.Show("Aborting client");
_gameClient.Abort();
}
}
catch(Exception ex)
{ MessageBox.Show(ex.ToString());}
}
EDIT #2
I found the mistake, on the service side i had delegates that were static. It doesn't throw this error when it's not static.
I have built a notification system with the following code:
class SignalRClient
{
HubConnection hubconn;
IHubProxy proxy;
public SignalRClient(string url)
{
hubconn = new HubConnection(url);
proxy = hubconn.CreateProxy("XXX.NotificationHub");
hubconn.Start().Wait();
}
public void SendMessage()
{
proxy.Invoke("LiveNotify", new { Application = "SRWinClient", Server = Environment.MachineName, Message = "This is a test", ImgId= 2 });
}
}
This works great when i trigger it from a test windows forms app (on a button click), but when i call if from a singleton object that i have it fails on the Start().Wait(). I have copy pasted the code and checked a number of times to make sure there were no typos.
Here is my notification singleton. It does more than the SignalR bit. it updates Databases and more, but here is the relevant parts:
public class CDSNotifier
{
private static object mLock = new object();
private static CDSNotifier mnotifier = null;
private bool enableSignalRNotifications = false;
private SignalRNotifier snotifier;
private CDSNotifier()
{
NameValueCollection appSettings = ConfigurationManager.AppSettings;
try
{
enableSignalRNotifications = Convert.ToBoolean(appSettings["EnableSignalRNotifications"]);
}
catch { };
if (enableSignalRNotifications)
{
snotifier = new SignalRNotifier(appSettings["SignalRHubURL"]);
}
}
public static CDSNotifier Instance
{
get
{
if (mnotifier == null)
{
// for thread safety, lock an object when
lock (mLock)
{
if (mnotifier == null)
{
mnotifier = new CDSNotifier();
}
}
}
return mnotifier;
}
}
public void Notify(int applicationId, int? companyId, string message, NotificationType type, string server)
{
.....
try
{
if (enableSignalRNotifications)
snotifier.SendMessage(applicationId, message, type);
}
catch { }
}
Exception that I am getting:
System.AggregateException
Message: One or more errors occured
StackTrace: at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
I finally figured it out. My notification system was a separate lib and my executable's bin was not getting the Newtonsoft.JSON dlls. I added the package using nuget to my primary projects and it worked like a charm.
#M.Babcock thanks for leading me in the right direction. i looked at the exceptions but i was looking at the one that said "InnerExceptions" (the one with s), that did not have any info. but when i looked in to "InnerException" i found more info.
I'm having some trouble unit testing a bit of code while utilising the Wcf Facility for Castle Windsor. It seems to refuse to include Exception Details when an Exception is thrown, I only get to see empty FaultExceptions. This is my test setup:
First, here's a stub of the service that I will be connecting to:
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public abstract class StubAilDataService : IAilDataService
{
public virtual Method1()
{
}
/* More methods */
}
Notice that I've specified IncludeExceptionDetailsInFaults and set it to true.
This is how I host the stubbed service:
private ServiceHost _host;
private StubAilDataService _rhinoService;
[TestFixtureSetUp]
public void FixtureSetup()
{
var sba = new ServiceDebugBehavior {IncludeExceptionDetailInFaults = true};
_rhinoService = MockRepository.GeneratePartialMock<StubAilDataService>();
_host = new ServiceHost(_rhinoService);
_host.AddServiceEndpoint(typeof(IAilDataService), new WSHttpBinding("wsSecure"), "http://localhost:8080/Service");
_host.Open();
_container.AddFacility<WcfFacility>().Register(
Component.For<IServiceBehavior>().Instance(sba),
Component.For<IAilDataService>()
.LifeStyle.PerWcfSession()
.ActAs(new DefaultClientModel
{
Endpoint =
WcfEndpoint.BoundTo(new WSHttpBinding("wsSecure"))
.At("http://localhost:8080/Service")
}) // More stuff
);
}
I've done a PartialMock in an attempt to keep the Include.. attribute on the mocked object.
And the test. Notice that I tell my mocked service to throw a very specific exception here.
[Test]
[ExpectedException(typeof(AggregateException))]
public void AnalyzeProductCreationJobs_Should_Throw_Aggregate_Exception_If_A_DataService_Call_Throws()
{
//Arrange
_rhinoService.Expect(
s => s.CategoryIsInAgility(Arg<string>.Matches(str => str.Equals("000103")), Arg<Settings>.Is.Anything))
.Throw(new FaultException<InvalidOperationException>(new InvalidOperationException("FAIL!")));
var product = new Product { CategoryCode = "000103" };
var analyzer = TypeResolver.Resolve<ProductAnalyzer>();
//Act
analyzer.AnalyzeProductCreationJobs(product);
}
And finally, the code I'm actually testing:
public class ProductAnalyzer
{
private readonly IDataServiceClient _dataClient;
public ProductAnalyzer(IDataServiceClient dataClient)
{
_dataClient = dataClient;
}
public IEnumerable<IAdsmlJob<CreateResponse>> AnalyzeProductCreationJobs(Product product)
{
IList<IAdsmlJob<CreateResponse>> creationJobs = new List<IAdsmlJob<CreateResponse>>();
var task = Task.Factory.StartNew(() =>
{
// This is where the exception set up in my .Expect gets thrown.
bool categoryIsInAgility = _dataClient.CategoryIsInAgility(product.CategoryCode);
// Logic
}); // Continued by more tasks
try
{ task.Wait(); }
catch (AggregateException ae)
{
ae.Flatten().Handle(ex => ex is TaskCanceledException);
}
}
I would expect the service to crash and throw the exception I've set it up to throw - but the Wcf Facility seems to strip away the exception that is thrown and replace it with an empty FaultException instead.
Am i missing something? There are quite a few components working together here - and I'm not 100% sure where things go wrong.
You have to explicitly declare the type of fault exception the method throws on the interface.
Example:
[ServiceContract(Namespace = "http://www.example.com")]
public interface IAilDataService
{
[OperationContract]
[FaultContract(typeof(OperationPermissionFault))]
[FaultContract(typeof(InvalidOperationException))]
void Method1();
}
See http://msdn.microsoft.com/en-us/library/system.servicemodel.faultcontractattribute.aspx