I have a WCF Service that should not enter the faulted state. If there's an exception, it should be logged and the service should continue uninterrupted. The service has a one-way operation contract and is reading messages from an MSMQ.
My problems are twofold:
The service appears to be swallowing
an exception/fault so I am unable to
debug it. How do I get the service
to expose the exception so that I
can log or handle it?
The service is
entering into a faulted state after
this exception is swallowed. How do
I prevent the service from entering
into a faulted state?
The official documentation on how to handle Faults is here:
Handling Exceptions and
Faults
Understanding State
Changes
with the main page being at Channel Model Overview
There's a nice state diagram showing how things happen:
Most, if not all exceptions can be seen in the WCF Trace (Configuring Tracing) and the trace is best viewed with the Service Trace Viewer.
Obviously, this is not something you should have running all day in a production environment, but it helps in troubleshooting anyway.
Apart from that, note that oneways may not run as a true "fire and forget" depending on the SessionMode you use. If you have your service configured for SessionMode.Allowed or even SessionMode.Required, the oneway operation will run as if it was not oneway at all (this can be observed when using oneways over the netTcpBinding). To be frank, however, I don't know if that changes the type of exceptions you can get, or when you get them. However, in any case, you should get an exception if the request could not be send at all. AFAIK, the oneway "ends" when it is successfully enqued on the server side. So there is some place for (WCF framework related) exceptions until then (serialization/deserialization comes to mind).
Then, such framework related exceptions are best seen (even an IErrorHandler doesn't get them all due to the fact when it is called in the request/response-flow) using the above mentioned trace / traceviewer.
Exceptions will fault the proxy. You can't AFAIK do much about that: don't cause exceptions ;-p
I'm a little surprised that one-way is still causing a problem, but for swallowing in general, there are 3 aspects:
are you throwing faults? or exceptions? it matters (and should be "faults")
as a hack, you can enable debug exception messages - but turn it off please!!!
are you "using" the service object? I've just blogged on this exact subject... basically, your "using" can swallow the exception.
3 options:
don't use "using"
subclass the proxy and override Dispose()
wrap it, as per the blog
Usually the WCF service is hosted in a ServiceHost, if the WCF-Service fails then the only option is to kill the WCF service and start a new one.
The ServiceHost has an event trigger "Faulted" that is activated when the WCF Service fails:
ServiceHost host = new ServiceHost(new Service.MyService());
host.Faulted += new EventHandler(host_faulted);
host.Open();
It is possible to get the exception causing the fault, but it requires a bit more work:
public class ErrorHandler : IErrorHandler
{
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
}
public bool HandleError(Exception error)
{
Console.WriteLine("exception");
return false;
}
}
public class ErrorServiceBehavior : IServiceBehavior
{
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)
{
ErrorHandler handler = new ErrorHandler();
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
dispatcher.ErrorHandlers.Add(handler);
}
}
}
ServiceHost host = new ServiceHost(new Service.MyService());
host.Faulted += new EventHandler(host_faulted);
host.Description.Behaviors.Add(new ErrorServiceBehavior());
host.Open();
Credits http://www.haveyougotwoods.ca/2009/06/24/creating-a-global-error-handler-in-wcf
I had an issue where the Channel remained in a faulted state after a ReceiveTimeout exception. This would cause the service to be rendered unusable by any subsequent connections.
The fix for recovering the service from the faulted state for me was to handle the Faulted event of the communication channel:
channelFactory = new ChannelFactory<IService>(endpoint);
channelFactory.Faulted += OnChannelFaulted;
var channel = channelFactory.CreateChannel();
Then define OnChannelFaulted:
void OnChannelFaulted(object sender, EventArgs e)
{
channelFactory.Abort();
}
Note: I am running the WCF config via code versus using bindings in the Web.config's.
About 2)...
The trick is that you should use "using" and should always call Abort() on the proxy that threw an exception. The article WCF Gotcha explains it all.
We use service class inspired by that article that wraps service calls. This is sample code from my project:
ServiceHelper<CodeListServiceClient, CodeListService.CodeListService>.Use(
proxy => seasonCodeBindingSource.DataSource = proxy.GetSeasonCodes(brandID);
);
And this is the code of ServiceHelper, slightly modified from the article. So far it has served us really well.
using System;
using System.ServiceModel;
namespace Sportina.EnterpriseSystem.Client.Framework.Helpers
{
public delegate void UseServiceDelegate<TServiceProxy>(TServiceProxy proxy);
public static class ServiceHelper<TServiceClient, TServiceInterface> where TServiceClient : ClientBase<TServiceInterface>, new() where TServiceInterface : class
{
public static void Use(UseServiceDelegate<TServiceClient> codeBlock)
{
TServiceClient proxy = null;
bool success = false;
try
{
proxy = new TServiceClient();
codeBlock(proxy);
proxy.Close();
success = true;
}
catch (Exception ex)
{
Common.Logger.Log.Fatal("Service error: " + ex);
throw;
}
finally
{
if (!success && proxy != null)
proxy.Abort();
}
}
}
}
Related
How can I get the full stack of an exception that's happening in an otherwise functioning Web application during SignalR connection setup?
Background
I'm part of a team maintaining a Web application with C# clients that uses an extremely basic SignalR setup (version 2.2) to effectively deliver push notifications about progress during long-running server processes. Like, out-of-the-box,
app.MapSignalR();
HubConnection connection = new HubConnection(_applicationConfiguration.ApiBaseUri + "/signalr");
await connection.Start();
basic. Some of our clients run on remoting services and periodically run into an issue where the other functions of the Web application work fine, but the client code that calls connection.Start() returns a 500 internal server error with no further information. They can address it by refreshing the remote connection but this is less than ideal, so I'm trying to get some information about where in the connection setup process this error is happening.
Problem
Following the information about setting up error handling for SignalR on MSDN, I've tried to simulate the problem by inserting the following pipeline module into the GlobalHost.HubPipeline:
public class HubErrorHandlingModule : HubPipelineModule
{
public override Func<IHub, Task> BuildConnect(Func<IHub, Task> connect)
{
throw new InvalidOperationException("Testing Connection Exceptions");
}
protected override void OnIncomingError(ExceptionContext exceptionContext,
IHubIncomingInvokerContext invokerContext)
{
// some logging happens here
base.OnIncomingError(exceptionContext, invokerContext);
}
}
and it kind of works, in that I can see the exception get thrown in the pipeline code, and my test C# client is also seeing a 500 internal server error with no further information.
But it also kind of doesn't work, in that I've dropped in breakpoints and the OnIncomingError code is never hit. That sort of makes sense, since it's not code in any Hub method that's causing the exception, but I don't know where this exception is happening; it could be anywhere during the client call to connection.Start.
I've also tried passing in an alternate HubConfiguration with EnableDetailedErrors = true but that doesn't seem to improve anything.
It doesn't really matter where I get the full stack trace, since I control both the server and the client code, but in order to understand their problem I need to see the full trace somewhere.
What I've Tried And Why It Doesn't Work
app.MapSignalR(new HubConfiguration { EnableDetailedErrors = true });
I think this is meant to show detailed errors from Hub processing, not connection handshaking? Supposedly it's meant to send a message tagged as an error that might be traced by the connection even if it's never bubbled up to any consumer. Unfortunately...
var writer = new StreamWriter("C:\\Logs\\ClientLog.txt");
writer.AutoFlush = true;
connection.TraceLevel = TraceLevels.All;
connection.TraceWriter = writer;
This does trace successful communication to the SignalR backend, once I remove the deliberate pipeline error. But when I set it back up, all I see is a failed attempt to establish the connection and a 500 internal server error. No trace.
<system.diagnostics>
<sharedListeners ... >
<switches ...>
<sources ...>
<trace autoflush="true" />
</system.diagnostics>
Set up both after the MSDN trace details and this commentary on GitHub. Neither set of details works. As I play around by moving the pipeline exception to different pipeline events, I can sometimes see a stack trace show up in the SignalR.HubDispatcher source mentioned only in the GitHub details, but it happens when I throw the exception after the connection's been established and what arrives at the client side is a different error than just a 500 internal server error, so that's probably happening too late to be whatever's going wrong at the client installation.
In my case I have to put the SignalR.cs in my root path.
Then in the view I include the script:
<script src="~/signalr/hubs"></script>
This is what my SignalR.cs looks like:
public class NotificationHub : Hub
{
public void SendUpdateNotification(string message)
{
// message = "show" / "hide"
if (message.Equals("show"))
Config._MaintenanceMode = true;
else
Config._MaintenanceMode = false;
// Call the broadcastUpdate method to update clients.
Clients.All.broadcastUpdate(message);
}
}
To handle errors that SignalR raises, you can add a handler for the error event on the connection object
connection.Error += ex => Console.WriteLine("SignalR error: {0}", ex.StackTrace);
To handle errors from method invocations, wrap the code in a try-catch block.
HubConnection connection = new HubConnection(_applicationConfiguration.ApiBaseUri + "/signalr");
try
{
await connection.Start();
}
catch (Exception ex)
{
Console.WriteLine("Error " + ex);
}
To enable detailed error messages for troubleshooting purposes,
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
App.MapSignalR(hubConfiguration);
In your code the hub pipeline module I do not see you are logging/printing the error
Console.WriteLine("Exception " + exceptionContext.Error.Message);
base.OnIncomingError(exceptionContext, invokerContext);
and now hook up the custom HubPipelineModule we've created, this is achieved in the startup class
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
GlobalHost.HubPipeline.AddModule(new HubErrorHandlingModule());
app.MapSignalR();
}
}
References:
SignalR Notify user about disconnections
SingalR How to Handle Errors
SignalR 500 Internal Server Error
I'm hosting WCF as Widnows Service but I have a problem with handling Faulted state of WCF channel. Faulted event on ServiceHost never rise up.
Hosting application:
protected override void OnStart(string[] args)
{
_serviceHost = new ServiceHost(typeof(WCF_FaultTest.Service1));
_serviceHost.Faulted += _serviceHost_Faulted;
_serviceHost.Open();
}
void _serviceHost_Faulted(object sender, EventArgs e)
{
// never raise up..
}
Faulted state I try to simulate like this:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
public class Service1 : IService1
{
public string GetFault()
{
throw new Exception("Should went to fault..");
}
Do I using it correctly? Thank you.
You are using more than one CommunicationObject. When you throw the exception in your service implementation the channel is faulted, but the host it is not. The ServiceHost.Faulted event does not apply in this case.
One thing to remember is that once a CommunicationObject enters the faulted state, it can no longer be used. The only thing to do with a faulted CommunicationObject is to close/abort. After your service throws the exception, if you create a new channel you can still call the service. Therefore the service is not faulted.
From an architecture point of view, a service host event is not the "right" place to implement error handling. In general you want error processing to be part of the service configuration. For example error handling in a ServiceHost event doesn't easily move to IIS hosting. Your comment makes it sound like IErrorHandler didn't meet your requirements. What requirement are you trying to implement?
We have the following code...
DiscoveryService.cs
[ServiceContract]
public interface IDiscoveryService
{
[OperationContract]
void PrintHello();
}
public class DiscoveryService : IDiscoveryService
{
public void PrintHello()
{
MessageBox.Show("Hello");
}
}
Server.cs
private void InitializeDiscovery()
{
Uri baseAddress = DiscoveryHelper.AvailableTcpBaseAddress;
ServiceHost host = new ServiceHost(typeof (DiscoveryService), baseAddress);
host.EnableDiscovery();
host.Open();
}
Client.cs
private void DiscoverAddressClick(object sender, EventArgs e)
{
EndpointAddress address = DiscoveryHelper.DiscoverAddress<IDiscoveryService>();
Binding binding = new NetTcpBinding();
IDiscoveryService proxy = ChannelFactory<IDiscoveryService>.CreateChannel(binding, address);
proxy.PrintHello();
(proxy as ICommunicationObject).Close();
}
Now, this code seems to work up until the point where we modify anything having to do with the Service Contract, at which point we get a TCP Exception, Error Code 10061 (Connection Actively Refused). However, we cant figure out who is refusing, or why. If we try to revert our code to a previous state, when it was working, we can't, it simply refuses to work after (it seems) we add / remove things from the project.
Every time I build I clean first. We're also following the instructions posted here.
Any thoughts?
I will begin by stating that I'm not all that familiar with WCF Discovery....though I may implement it in our new server stack. But one thing I do not see here is the presence of a proxy server in what you present here.
As I understand it from what I've read on MSDN your WCF service will basically register it's presence to a proxy server running on the network. Your client will then 'discover' your service server via the DiscoveryProxy server. That may be the piece of the plumbing you are missing.
You current implementation of the server will close down the server as soon as the InitializeDiscovery Method is complete because your host only has function scope and will be cleaned up by the garbage collector unless you keep a reference somewhere else.
I want to write an IErrorHandler implementation that will handle AuthenticationException instances (a proprietary type), and then in the implementation of ProvideFault provide a traditional Http Response with a status code of 403 as the fault message.
So far I have my first best guess wired into a service, but WCF appears to be ignoring the output message completely, even though the error handler is being called.
At the moment, the code looks like this:
public class AuthWeb403ErrorHandler : IErrorHandler
{
#region IErrorHandler Members
public bool HandleError(Exception error)
{
return error is AuthenticationException;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
//first attempt - just a stab in the dark, really
HttpResponseMessageProperty property = new HttpResponseMessageProperty();
property.SuppressEntityBody = true;
property.StatusCode = System.Net.HttpStatusCode.Forbidden;
property.StatusDescription = "Forbidden";
var m = Message.CreateMessage(version, null);
m.Properties[HttpResponseMessageProperty.Name] = property;
fault = m;
}
#endregion
}
With this in place, I just get the standard WCF html 'The server encountered an error processing the request. See server logs for more details.' - which is what would happen if there was no IErrorHandler. Is this a feature of the behaviours added by WebServiceHost? Or is it because the message I'm building is simply wrong!? I can verify that the event log is indeed not receiving anything.
My current test environment is a WebGet method (both XML and Json) hosted in a service that is created with the WebServiceHostFactory, and Asp.Net compatibility switched off. The service method simply throws the exception in question.
try this:
Returning Error Details from AJAX-Enabled WCF Service
and this
http://zamd.net/2008/07/08/error-handling-with-webhttpbinding-for-ajaxjson/
I want to know whether unhandled exception will make WCF service crash. I have written the following program which shows unhandled exception in a thread started by WCF service will make the whole WCF service crash.
My question is, I want to confirm whether unhandled exception in threads (started by WCF service) will make WCF crash? My confusion is I think WCF should be stable service which should not crash because of unhandled exception.
I am using VSTS 2008 + C# + .Net 3.5 to develop a self-hosted Windows Service based WCF service.
Here are the related parts of code,
namespace Foo
{
// NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in Web.config.
[ServiceContract]
public interface IFoo
{
[OperationContract]
string Submit(string request);
}
}
namespace Foo
{
// NOTE: If you change the class name "Service1" here, you must also update the reference to "Service1" in Web.config and in the associated .svc file.
public class FooImpl : IFoo
{
public string Submit(string request)
{
return String.Empty;
}
}
}
namespace Foo
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
ServiceHost host = new ServiceHost(typeof(FooImpl));
protected override void OnStart(string[] args)
{
host.Open();
// start a thread which will throw unhandled exception
Thread t = new Thread(Workerjob);
t.Start();
}
protected override void OnStop()
{
host.Close();
}
public static void Workerjob()
{
Thread.Sleep(5000);
throw new Exception("unhandled");
}
}
}
An unhandled exception on the service side will cause the channel (the connection between the client and the server) to "fault" - e.g. to be torn down.
From that point on, you cannot call from the client using the same proxy client object instance anymore - you'll have to re-create the proxy client.
Your best bet is to handle all error on the server side whenever possible. Check out the IErrorHandler interface, which you should implement on your service implementation class, to turn all unhandled .NET exceptions into either SOAP faults (which will NOT cause the channel to fault), or to report / swallow them entirely.
Marc
Yes, an unhandled exception in a thread will take the process down.
This process will crash:
static void Main(string[] args)
{
Thread t = new Thread(() =>
{
throw new NullReferenceException();
});
t.Start();
Console.ReadKey();
}
This one will not:
static void Main(string[] args)
{
Thread t = new Thread(() =>
{
try
{
throw new NullReferenceException();
}
catch (Exception exception)
{
Console.WriteLine(exception.ToString());
}
});
t.Start();
Console.ReadKey();
}
The default behavior of the WCF runtime is to swallow all but a few types exceptions. So if your code throws an exception down the stack to the WCF runtime (such as if you throw from a WCF operation), it will NOT crash the app (unless it is deemed a "fatal" exception, such as OOM, SEHException, etc.). If the exception is not part of the operation's fault contract, then the channel will be faulted, otherwise not.
If the WCF runtime is not under your code on the stack, then the exception /will/ crash the process.
This is similar to the ASP.NET runtime.
If you would like to screen for exceptions flying out of WCF operations in a general way, I recommend using the IOperationInvoker interface. You can also use IErrorHandler, but your IErrorHandler implementation will be notified of exceptions other than those thrown from "user code" (WCF operations), such as SocketAbortedExceptions on WCF internal I/O threads, which are probably not interesting to you.
If you don't handle an exception it gets passed on the operating system and it will respond by killing what ever application caused the exception.
Why don't you just add a try/catch to handle the exceptions so that your service is not killed ?
If you don't have proper error handling it will make the program crash. Its good practise to put a
try{//do something
}
catch{ //handle errors
}
finally{//final clean up
}
block in your code to make sure that if it does throw an exception is to handle it gracefully. examples at http://msdn.microsoft.com/en-us/library/fk6t46tz(VS.71).aspx
You can make use of FaultException to communicate errors to the client side and keep the logic in the service.
Check this example, hope it helps you.