The error message is following:
This channel can no longer be used to send messages as the output
session was auto-closed due to a server-initiated shutdown. Either
disable auto-close by setting the
DispatchRuntime.AutomaticInputSessionShutdown to false, or consider
modifying the shutdown protocol with the remote server.
It happens, when I create a web request to a WCF router (wsHttpBinding or BasicHttpBinding to NetTcpBinding) and the router then requests WinService. Once the WinService throws an Exception, the next requests gives the error message above. It is created by the WCF router.
There was no solution anywhere, I've spend days finding one.
Links to similar problems without solution:
WCF Communication error occurs randomly and impossible to catch the reason why
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/3f19cdaa-f426-4902-a93a-2654c7f19788/
The working solution I did is following:
Do not throw an Exception, throw FaultException
How to do that:
On the WinService interface define a response code enum (example following)
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "3.0.4506.2152")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "blah")]
public enum ErrorCode
{
ERROR
}
or just
public enum ErrorCode
{
ERROR
}
then instead of an Exception throw FaultException using defined enum:
throw new FaultException(ErrorCode.ERROR, new FaultReason("blah"), new FaultCode("Sender"));
And that's it! Now you can send request that generate this exception and it doesn't close the channel
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 have a WCF service that throws FaultExceptions when something goes wrong. Some of the error classes being thrown works just fine, yet some of the other doesn't work at all and give the following error:
An error occured while receiving the HTTP response to http://localhost/MyService. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down).
With an inner exception saying
The underlying connection was closed: An unexpected error occurred on a receive.
My code works thusly:
Server
public Stream DoSomething() {
if (someCondition) {
if (fileExists) {
return new Stream(); // I know I can't do this, but for example purpose only :)
}
throw new FaultException<System.IO.FileNotFoundException>(new FileNotFoundException());
}
throw new FaultException<MyException>(new MyException());
}
Exception class
public class MyException: Exception
{
}
Client
try {
wcfClient.DoSomething();
} catch (FaultException<FileNotFoundException>) {
// This works just fine
} catch (FaultException<MyException>) {
// This gives the error listed above
}
Both FileNotFoundException and MyException are set up in the contract:
[FaultContract(typeof(FileNotFoundException))]
[FaultContract(typeof(MyException))]
Why does FaultException<FileNotFoundException> work as expected, but not FaultException<MyException>?
If I remove Exception inheritance from MyException everything works as it should (but I want consistency, so I want it to be an actual exception). There is no change if Exception inheritance is left in, but it is decorated with [DataContract].
Why is that? FileNotFoundException inherits from Exception too. One works, the other doesn't. Frustrating!
P.S.: Both the server and the client share the same assembly the interfaces and classes are defined in, so there shouldn't be any contract mismatches.
Your exception should probably be [Serializable]. I think that would solve your problem already.
As a best practice for Exceptions you should also implement the three constructors.
I have a question regarding WCF fault exceptions. I am implementing the IErrorHandler interface and creating a FaultException.
My question is this: When am I creating a FaultException, is there a pattern that I must follow to send a friendly error message to the client?
I log the actual exception using the HandleError method to the database and creating a FaultException in the ProvideFault method.
Given delow, there is my sample implementation of IErrorHandler interface.
public bool HandleError(Exception error)
{
System.Diagnostics.Debug.WriteLine(error.Message);
// Log the error to the Db
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
// Here is a sample that I was playing with.
MessageFault faultException;
if(error is DataException)
faultException = new FaultException<string>(ErrorStrings.DatabaseOpenError, new FaultReason(ErrorStrings.DatabaseOpenError)).CreateMessageFault();
else if (error is NullReferenceException)
faultException = new FaultException<string>(ErrorStrings.NullDataError, new FaultReason(ErrorStrings.NullDataError)).CreateMessageFault();
else
faultException = new FaultException<string>(ErrorStrings.GeneralError, new FaultReason(ErrorStrings.GeneralError)).CreateMessageFault();
fault = Message.CreateMessage(version, faultException, "");
}
I need some clarity on what exactly has to be done inside ProvideFault method to return a friendly Fault to the user. I am also planning to use localization to display errors. Not sure if this will be done by the client or if service should send localized messages.
Based on what I read, I should not send information of the stack from the error or EntityFramework errors, like EntityValidation errors and so on, to the client due to security reasons.
In this case, will I need to check for the type of exception and mine the details to be more appropriate before sending to the client?
The main requirement is to use the FaultContractAttribute so WCF understands the service contract being fulfilled. Please see http://msdn.microsoft.com/en-us/library/ms752208(v=vs.110).aspx
WCF will then also make sure your WSDL reflects your fault contracts.
I have a program that calls an external web service, and I want to present the user with a friendly dialog if e.g. the server is down, someone cut the cable etc. Assuming the following code
try {
client.MyWebService()
}
catch(? ex)
{
// display friendly dialog explaining what went wrong
}
what exception(s) should I put in place of the question mark in the code? It is kind of hard to actually test situations like this when everything is working smoothly and I have no control over the external part, so some insight would be appreciated.
Thanks!
The first thing to do is take advantage of the .Faulted event on your proxy, which you can wire up like this:
((ICommunicationObject)client).Faulted += new EventHandler(client_Faulted);
In your client_Faulted event handler you can then try re-connecting, or shifting to a backup server, or disabling the UI, logging the error, or displaying a message there.
It's obviously still good practice to wrap each call in a try-catch as well, but the .Faulted event can let you deal with most channel problems even earlier.
As for the exception itself, you can have your service throw a FaultException that gets passed back to the client with the details you provide. See an example of its use at this blog posting.
You won't get a FaultException if the channel itself fails (FaultException is a way for the server to communicate its own internal faults to the client).
For channel faults, you may get a CommunicationException or TimeoutException.
Finally, take a look at this project on Codeplex for generating Exception Handling WCF proxies. It may give you a more flexible way of handing faults.
It's not really the client's job to provide as much detail as possible. The maximum amount you really have to provide at the client side is as much as you get back in your exception.
var userName = "bob";
try
{
client.MyWebService(userName);
}
catch(Exception ex)
{
//Maybe we know WellKnownExceptions and can provide Foo advice:
if (ex is WellKnownException)
{
Console.WriteLine("WellKnownException encountered, do Foo to fix Bar.");
}
//otherwise, this is the best you can do:
Console.WriteLine(string.Format(
"MyWebService call failed for {0}. Details: {1}", userName, ex));
}
I was asking the same question, as I have to implement some exception handling on web services calls at my client application, so I ended up here. Although it's an old question, I'd like to give my two cents, updating it a little bit.
The answer given by C. Lawrence Wenham was already very good and points to some interesting information, although the blog link is broken and Codeplex is now archived.
I found those articles very valuables:
Sending and Receiving Faults
https://learn.microsoft.com/en-us/dotnet/framework/wcf/sending-and-receiving-faults
Expected Exceptions
https://learn.microsoft.com/en-us/dotnet/framework/wcf/samples/expected-exceptions
And this article from Michèle Leroux Bustamante (apparently the creator of the Exception Handling WCF Proxy Generator CodePlex project) is very insighful also:
An Elegant Exception-Handling Proxy Solution
http://www.itprotoday.com/microsoft-visual-studio/elegant-exception-handling-proxy-solution
I'm still studying the subject but I guess I'll use a lot of ideias from Michèle. I'm just a little bit concerned about using reflection to call the web service's methods, but I wonder if this would have any impact in such kind of operation, that is inherently slow already.
Just to answer here explicitly what was asked originally, which are the exceptions that could be tested against a web service call:
string errorMessage = null;
// A class derived from System.ServiceModel.ClientBase.
MyWebService wcfClient = new MyWebService();
try
{
wcfClient.Open();
wcfClient.MyWebServiceMethod();
}
catch (TimeoutException timeEx)
{
// The service operation timed out.
errorMessage = timeEx.Message;
}
catch (FaultException<ExceptionDetail> declaredFaultEx)
{
// An error on the service, transmitted via declared SOAP
// fault (specified in the contract for an operation).
errorMessage = declaredFaultEx.Detail.Message;
}
catch (FaultException unknownFaultEx)
{
// An error on the service, transmitted via undeclared SOAP
// fault (not specified in the contract for an operation).
errorMessage = unknownFaultEx.Message;
}
catch (CommunicationException commEx)
{
// A communication error in either the service or client application.
errorMessage = commEx.Message;
}
finally
{
if (wcfClient.State == CommunicationState.Faulted)
wcfClient.Abort();
else
wcfClient.Close();
}
As stated by the articles, the order the exceptions are catched is important, since FaultException<TDetail> derives from FaultException, and FaultException derives from CommunicationException.
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/