I am getting this error in wcf - c#

When I retrieve more than 200 000 records from server to clients I am getting this error:
The underlying connection was closed:
A connection that was expected to be kept alive was closed by the server.
What's going wrong here?

Many things can lead to this issue in WCF. The best way to solve is definetly to add trace log. Add the following code to your configuration file to active the tracing :
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="traceListener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="e:\path_tolog\WebTrace.svclog" /> <-- Path to the log file
</listeners>
</source>
</sources>
</system.diagnostics>

As others have said, without seeing any code, we can only guess, but I have seen similar problems when trying to send an unenumerated query across WCF.
For example, if you have something like (Warning: Air code!) this..
var data = ctx.Customers.Where(c => c.CustType == 1);
...and you try and return this from a WCF service method, you'll get the exception you mentioned. This is because the query is set up, and sent out to WCF where it is serialised, which fails as the serialisation attempts to enumerate the query after the connection has been closed.
The answer is to force enumeration of the query before you return it. You can do this by adding .ToList() to the end of the query (amongst other ways).
As I said, without seeing any code this is a complete guess, but I ahve had the same exception in these circumstances, so it's worth checking.

Related

Casting to an invalid enum value results in unspecified exception on clientside

I know that casting an integer to an invalid enum value does not result in an exception in C# due to Flags. Here I was, specifying a table in a DB table and getting its values 1-3 with EntityFramework. On my serverside I cast the values into an enum XyzType ranging from 0-2, which obviously generates the invalid value (XyzType)3. Now i put this value in a XyzDTO and send it to a WCF client. Which upon deserialization fails with this very vague description:
Now i've read some other posts discussing exceptions caused by deserializing invalid XML and it all makes sense.
My question is, how come I did not get any useful information as to what the cause was at all? I spent the last 1.5 hours with this bug, until i figured the difference between the enum and the DB values. Is it considered a flaw in the WCF error handling that no useful info was given? If so, should MS be notified? Do you have any good practices as to how to avoid scenarios like this in the future?
EDIT: Please note i do not have a web.config. My serverside is a WCF service within a windows service, ie. i have app.config.
EDIT2: There seems to me some misunderstanding regarding this issue and what ive tried. Inspecting the InnerExceptions of the CommunicationException in the debugger provides no useful information at all. Also i already have "includeExceptionDetailsInFaults" = true on serverside, but the exception is not thrown by the serverside! It is caused during deserialization on clientside.
EDIT3: Some answers have suggested activating tracing on clientside. I have now attempted this, but apparantly for this issue it does not provide any useful information either. Here is a link to the output.
When discussing enums and WCF, ensure the values are serialized/deserialized by marking up the enum with the DataContract and EnumMember attributes as follows:
[DataContract(Namespace = Namespaces.V1)]
public enum AreaType : int
{
[EnumMember]
Unknown = 0,
[EnumMember]
Urban = 1,
[EnumMember]
Suburban = 2,
[EnumMember]
Rural = 3
}
It seems obvious, but also be aware that the default value is 0. As khlr mentioned, you can activate tracing. You will want to set the customErrors mode to "Off" and compilation for debug to "true" in your web.config while in Development.
<system.web>
<compilation debug="true" />
<customErrors mode="Off" />
</system.web>
Once you've moved off development, you'll want to provide a custom error page and set debug="false".
<system.web>
<compilation debug="false" />
<customErrors mode="RemoteOnly" defaultRedirect="ErrorRedirectPage.html" />
</system.web>
You'll also want to give some thought and design consideration to exception handling. You'll need to ensure you do not lose info. on the exception if you're rethrowing the exceptions. I like to use a simple logging framework, such as NLog, to log the exception, then I'll rethrow the exception back to the original method in the service where I wrap the exception in a FaultException where T is a class that I create for serializing and holding exception information. For example:
[DataContract(Namespace=Namespaces.V1)]
public class MyFaultException
{
[DataMember]
public string Reason { get; set; }
public MyFaultException()
{
this.Reason = "Service encountered an error";
}
public MyFaultException(string reason)
{
this.Reason = reason;
}
}
And in my service method:
try
{
//...
}
catch (Exception ex)
{
// Asynchronously log the error message in a helper class using NLog
LogHelper.LogException(ex, "Error calculating blah.", LogLevel.Error);
throw new FaultException<MyFaultException>(
new MyFaultException(ex.Message), new FaultReason(ex.Message));
}
You might want to define your own classes that derive from Exception to throw your own exceptions.
It's almost always a good idea to activate tracing to get some more detailed informations about the error:
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="traceListener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "c:\log\Traces.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
You can configure tracing in your server's and client's web- or app.config files to get details from both sides.
Edit:
<serviceDebug includeExceptionDetailInFaults="true" /> makes your service transport an occured exception (see here for more details) to the client. If the client doesn't handle that fault, you might won't notice it.
You're having problems with serialization/deserialization and as others already suggested you need more logging. And you've enabled some of it, but not all and not specific for serialization.
Try to use following config for logging:
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="traceListener" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="traceListener" />
</listeners>
</source>
<source name="System.Runtime.Serialization"
switchValue="Information">
<listeners>
<add name="traceListener" />
</listeners>
</source>
</sources>
<sharedListeners>
<add name="traceListener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "c:\log\Traces.svclog" />
</sharedListeners>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging
logEntireMessage="true"
logMessagesAtServiceLevel="true"
maxSizeOfMessageToLog="16777216"/>
</diagnostics>
</system.serviceModel>
</configuration>
Here I added two additional trace sources (and enabled message logging): System.Runtime.Serialization will produce any errors (if any) regarding serialization/deserialization process. And message logging will help you understand whether you receive anything on client side.
From callstack in the log you've published it's clear to me that exception happens on the server side. But message logging will show this better.
If you want to use Enum in WCF, you need to define 0 value for Enum. It is very important.
public enum MyEnum{
Default = 0,
SomeValue1 = 1,
SomeValue2= 2,
....
}

Add a default TraceListener for all TraceSources in App.config

How can I define a default TraceListener, that is automatically added to all TraceSources, in a net 4.0 c# project?
Currently I have to list every named TraceSource I use in the App.config file like this:
<system.diagnostics>
<sharedListeners>
<add name="MyListener" type="MyListenerType,MyAssemblyName" />
</sharedListeners>
<sources>
<source name="Class1" switchValue="All">
<listeners><add name="MyListener"></add></listeners>
</source>
<source name="Class2" switchValue="All">
<listeners><add name="MyListener"></add></listeners>
</source>
<source name="Class3" switchValue="All">
<listeners><add name="MyListener"></add></listeners>
</source>
... repeat for a gazillion classes ...
</sources>
<system.diagnostics>
I am using a SharedListener that should receive all outputs from all TraceSources, unless otherwise specified. With the above syntax, this requires a manual entry for each TraceSource.
Whenever I introduce a new class with a new TraceSource, I have to update the App.Config. If multiple programs use that assembly, I have to update multiple App.Config. A spelling mistake while updating these entries will not produce any error, it will just silently omit all trace output from the correct source.
Is there a way I can set a default TraceListener via App.config, so that I only have to name specific TraceSources if I want to deviate from the default?
I didn't find a great solution to this, so what I did was at least centralize the creation of TraceSources. Then I can add any of the 'trace' listeners in app.config to these newly created sources:
TraceSource toReturn = new TraceSource(name, filterLevel);
//remove the default trace listener; don't 'clear' the listeners entirely, because that would undo changes made in app.config; this is a decent compromise
toReturn.Listeners.Remove("Default");
//add all global trace listeners from the app.config
toReturn.Listeners.AddRange(Trace.Listeners);
return toReturn;
Now any listeners I add to <system.diagnostics> \ <trace> \ <listeners> will be added to all trace sources I create with this code.
You could add a default listener in the machine config, but that would affect more apps than you want to affect.

Regarding Enable Tracing in WCF

i go through this msdn link http://msdn.microsoft.com/en-us/library/ms733025%28v=vs.110%29.aspx
here is the full settings
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="CardSpace">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.IO.Log">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.Runtime.Serialization">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.IdentityModel">
<listeners>
<add name="xml" />
</listeners>
</source>
</sources>
<sharedListeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="c:\log\Traces.svclog" />
</sharedListeners>
</system.diagnostics>
</configuration>
but do not understand
why so many source & listener tag what is the meaning of having multiple source & listener tag ??
if possible please explain regarding multiple source & listener tag in config setting.
another point is
i enable the tracing but saw no file was created in this folder c:\log\Traces.svclog
so someone advise me that run the apps with admin privileged. when i distribute my apps to anyone then how do i know the person has admin privileged or not?
guide me. thanks
Most of your questions are answered inside the linked article
System.ServiceModel.MessageLogging: Logs all messages that flow through the system.
System.Runtime.Serialization: Logs when objects are read or written.
etc. You can log different information on different trace level (e.g. errors to database, warnings to xml file).
to another point:
You can for example request admin context as asked and answered here How to request administrator permissions when the program starts?
OK, so you have different sources because you may want to log problems/messages in different portions of the program. Most inportant for a WCF web service is the System.ServiceModel since that's going to capture the WCF in/out traffic, but you might also want to log trouble with your serialization, IO or IdentityModel (authentication/Authorization). So based on your config, you've got five sources all of which will be using the shared listener, named XML, which will log your text. That's what's going on here in a nutshell, but there's more.
"Can't see c:\log\Traces.svclog" ... if your WCF service is running and responding to requests, you should see something. If not, make sure you're running your service as "administrator", or the ID underwhich you're running your servce has read/write access to the folder.
"When i distribute my apps to anyone then how do i know the person has admin privileged or not?" OK, yes, I can see this as an issue. Here's a block of code, setting a boolean, you could use to 1) determine if the program is run as "admin", and if not B) instruct the user to re-start the program under the proper "admin" rights:
private void GetServicePermissionLevel()
{
bool bAdmin = false;
try {
SecurityIdentifier sidAdmin = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
AppDomain myDomain = Thread.GetDomain();
myDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal myPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;
if (myPrincipal.IsInRole(sidAdmin)) {
bAdmin = true;
} else {
bAdmin = false;
}
} catch (Exception ex) {
throw new Exception("Error in GetServicePermissionlevel(): ");
} finally {
_ServiceRunAsAdmin = bAdmin;
}
}
Also, if you're trying to debug host-side problems in your WCF service, you might want to turn on this parameter for your web host interface: IncludeExceptoinDetailsInFaults = True. It's false by default, but if you set this to true to expose more information about WCF service faults, make sure you turn it off before going to production.
Here's an additional URL to consider for your setup: http: //www.topwcftutorials.net/2012/06/simple-steps-to-enable-tracing-in-wcf.html

Activating logging for a Winform Application

I came across this: Winforms logging framework
But, I cannot get it working.
In the app.config, I have the following:
<system.diagnostics>
<trace autoflush="false" indentsize="4">
<listeners>
<add name="yourName" type="System.Diagnostics.TextWriterTraceListener" initializeData="c:\mylogfile.txt" />
</listeners>
</trace>
</system.diagnostics
In my code, I have the following to write to the log file:
Trace.Write("test");
Trace.TraceError("There's been an error captain: {0}", e);
Trace.TraceWarning("The system broke but don't worry.");
Trace.TraceInformation("Starting up the engines.");
The file is created. But nothing is written to it. Trace is turned on in visual studio.
Not sure what is missing here.
You've turned off autoflush. Try setting autoflush to true or calling Trace.Flush at the end of your code sample.

ASP.NET Webservice - Trace slows process when remotely called

We have a webservice which was running fine until recently.
When called locally the everything works fine, but when called remotely it takes up to 30sec to get the response. Not only for the the webmethod calls but also for plain calls to the asmx or for the wsdl.
The trace shows a gap between the return from GetHandler and the call to ProcessRequest.
Do you have any ideas of what could cause the issue at that point (only for remote calls) ?
Here is an extract of the service log showing the time gap when making a get to the .asmx from a browser :
System.Web.Services.Asmx Information: 0 : Return from IHttpHandlerFactory.GetHandler
Caller: System.Web.Services.Protocols.WebServiceHandlerFactory#23522948::GetHandler()
ProcessId=6420
LogicalOperationStack=
ThreadId=7
DateTime=2013-09-23T14:35:36.3381748Z
Timestamp=3850992018156
System.Web.Services.Asmx Information: 0 : Calling IHttpHandler.ProcessRequest
Caller: System.Web.Services.Protocols.SyncSessionlessHandler#41622463::ProcessRequest()
Request Host Address: **.**.**.**
Request Host Name: ***
Request Url: [GET] http://***/***.asmx
ProcessId=6420
LogicalOperationStack=
ThreadId=7
DateTime=2013-09-23T14:35:48.3970521Z
Timestamp=3851164660296
System.Web.Services.Asmx Information: 0 : Calling Void Documentation()
Method: System.Web.Services.Protocols.DocumentationServerProtocol#31364015::Documentation()
Caller: System.Web.Services.Protocols.SyncSessionlessHandler#41622463::Invoke()
ProcessId=6420
LogicalOperationStack=
ThreadId=7
DateTime=2013-09-23T14:35:48.3970521Z
Timestamp=3851164663918
Thank you
EDIT
After comparing the webservice with another one we have I finally found the origin of the problem : It was the trace itself. Once disabled evrything worked fine remotely.
I understand that tracing take time, but 30sec seems a lot and why would it take more time only for remote calls ?
As explain in the comment there is no authentication set up and the pool user has sufficiemt right since trace is actually written. Any ideas ?
Here is the trace setting
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.Web.Services.Asmx">
<listeners>
<add name="AsmxTraceFile" type="System.Diagnostics.TextWriterTraceListener" initializeData="c:\local.log" traceOutputOptions="LogicalOperationStack, DateTime, Timestamp, ProcessId, ThreadId" />
</listeners>
</source>
</sources>
<switches>
<add name="System.Web.Services.Asmx" value="Verbose" />
</switches>
</system.diagnostics>

Categories

Resources