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
Related
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,
....
}
For some reason I'm getting a "Failed to execute the command 'BulkInsertCommand' for table" and the error is caused by "Operand type clash: bigint is incompatible with uniqueidentifier" but I would think this can't be, because the fields in the database wouldn't allow the wrong input to begin with. I'm not sure if setting up a trace listener is going to help but at this point I can't see any other information about this error.
I'm trying to set up a sync listener but I can't find any information on how to set it up right, even on the Microsoft page where it says "Complete Code Example" and yet there is no code.
This is how I've set up listeners before. What do I need to change for it to listen to sync?
C#
private static readonly TraceSource ClientTraceSource = new TraceSource("ClientTraceSource");
web.config
<system.diagnostics>
<trace autoflush="true" indentsize="4" />
<sources>
<source name="ClientTraceSource" switchValue="Error,Information" switchType="System.Diagnostics.SourceSwitch">
<listeners>
<add name="myListener" />
</listeners>
</source>
</sources>
<sharedListeners>
<add name="myListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="XMLValidationErrorLog.txt" traceOutputOptions="DateTime">
</add>
</sharedListeners>
I want to rant and rave, really, really bad because this just seems completely unbelievable. Instead, I'm going to try and describe my situation as clearly as possible and hope that someone will tap me on the shoulder and point out my obvious error and let me carry on merrily.
I have a client/server application where the server is a set of IIS hosted WCF services. Thus, there are contracts and I've got service code which implements them. When I publish Now, I'm having a problem with a duplex contract over a nettcp binding which does not stay alive after the first response even though the client channel is cached on the server for later use in a static list, is never closed, has timeouts set appropriately, etc but the bugger doesn't want to work.
So I figured I'd add some traces to write out some extra information about where in my service implementation code it could be having a problem. This is in addition to the System.ServiceModel trace source I have set up which logs all of the service model stuff and thankfully has been working without a problem for a while now. Below are two different versions of the relevant section of my web.config which I have tried in an attempt to get regular tracing to write to a file:
1:
<system.diagnostics>
<trace autoflush="true" indentsize="4">
</trace>
<sources>
<source name="System.ServiceModel" switchValue="Warning" propagateActivity="true">
<!--use switchValue="All" or "Verbose" for more information-->
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="DuplexSource" switchValue="All" propagateActivity="true">
<listeners>
<add name="txt" />
</listeners>
</source>
</sources>
<sharedListeners>
<remove name="Default" />
<add name="txt" type="System.Diagnostics.TextWriterTraceListener" initializeData="c:\Logs\XXXErrorLog.txt" traceOutputOptions="Callstack" />
<add name="xml" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\Logs\ServerTraces.svclog" />
</sharedListeners>
When I have it set thusly, I create a TraceSource object in my service code, TraceSource duplexSource = new TraceSource("DuplexSource");, then I use that trace source to write out statements. The file is never created, it is never attempted to be created (using Process Monitor I can see that it never attempts). The file permissions are wide open and the other log file for the xml listener works wonderfully.
2, I've also tried a more straight forward Trace configuration:
<system.diagnostics>
<trace autoflush="true" indentsize="4">
<listeners>
<add name="txt" />
</listeners>
</trace>
<sources>
<source name="System.ServiceModel" switchValue="Warning" propagateActivity="true">
<!--use switchValue="All" or "Verbose" for more information-->
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="xml"/>
</listeners>
</source>
<sharedListeners>
<remove name="Default" />
<add name="txt" type="System.Diagnostics.TextWriterTraceListener" initializeData="c:\Logs\XXXErrorLog.txt" traceOutputOptions="Callstack" />
<add name="xml" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\Logs\ServerTraces.svclog" />
</sharedListeners>
</system.diagnostics>
Again, the log file is never even attempted to be created. Now, I've checked at runtime that I can write a file to that directory by actually doing so, then I wrote to that test file the contents of the Trace.Listeners collection to verify my listener was there, which it is. I even then called directy into the Listener's write method and this actually does get the file to be created and the WriteLine call successfully writes to the file as expected. Using System.Diagnostic.Trace.WriteLine does nothing however.
Any ideas of what could be causing this?
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.
I have set of web services and I want to add a trace layer.
I don't want to modify each web service since I have many.
I would like to write log every entering to a web service: name of web service and parameters.
What is the best way to do so?
P.S. I am using asp.net and C#.
EDIT:
I only want to wrap the web services as each one will have log(..) at the beginning.
A common way to achieve this is to inject a SOAP extension. From there you can intercept every request/response packet in raw SOAP. The sample shows how to implement one, and the explanation describes how it works and how to configure it.
Sample:
http://msdn.microsoft.com/en-us/library/system.web.services.protocols.soapextension.aspx
Explanation:
http://msdn.microsoft.com/en-us/library/esw638yk(vs.71).aspx
Configuration:
http://msdn.microsoft.com/en-us/library/b5e8e7kk(v=vs.71).aspx
<configuration>
<system.web>
<webServices>
<soapExtensionTypes>
<add type="{Type name}, {Assembly}" priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
Add a Global Application Class Global.asax file to your project and add the logging logic to the Application_BeginRequest() method. The sender object will contain the HTTP Request and parameters. You can filter for just .asmx requests and log those.
protected void Application_BeginRequest(object sender, EventArgs e)
{
}
EDIT--
Give PostSharp a try. It's the easiest way to get this functionality. For posterity I will leave my posting below but just ignore it and use PostSharp.
If your web services are WCF then you should check out http://msdn.microsoft.com/en-us/magazine/cc163302.aspx.
At each step along the way they provide extensibility points that you can plug into. You can use these extensibility points to implement a wide variety of custom behaviors including message or parameter validation, message logging, message transformations.
No doubt this is the way to go for WCF services. Otherwise, if they are just web services then you can use the Unity framework and hookup and Interceptor to do the same thing.
If the progamming language is not important, you may put Apache Synapse as proxy in front of your services. Your clients will then send the requests to Synapse, which will delegate the requests to your original services. The proxy can be configured to do something with the requests in between, such as logging.
Please see the following links for more information:
http://synapse.apache.org/Synapse_Configuration_Language.html#proxy,
http://synapse.apache.org/Synapse_Configuration_Language.html#send,
http://synapse.apache.org/Synapse_Configuration_Language.html#log
A combination of the following examples could work for you:
http://synapse.apache.org/Synapse_Samples.html#Sample0
http://synapse.apache.org/Synapse_Samples.html#ProxyServices
e.g.:
<definitions xmlns="http://ws.apache.org/ns/synapse"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ws.apache.org/ns/synapse http://synapse.apache.org/ns/2010/04/configuration/synapse_config.xsd">
<proxy name="StockQuoteProxy">
<target>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<outSequence>
<!-- log all attributes of messages passing through -->
<log level="full"/>
<!-- Send the message to implicit destination -->
<send/>
</outSequence>
</target>
<publishWSDL uri="file:repository/conf/sample/resources/proxy/sample_proxy_1.wsdl"/>
</proxy>
How about writing your own HttpModule? That would negate the need to touch the existing web service code. You would just need to add your module to each web.config file.
I maintain an Open source web services framework that lets you simply achieve this by having all web services inherit from a base class and do your own logging.
Here is an example of a base-class where I maintain a distributed rolling log for all exceptions in redis - a very fast NoSQL data store:
public object Execute(TRequest request)
{
try
{
//Run the request in a managed scope serializing all
return Run(request);
}
catch (Exception ex)
{
return HandleException(request, ex);
}
}
protected object HandleException(TRequest request, Exception ex)
{
var responseStatus = ResponseStatusTranslator.Instance.Parse(ex);
if (EndpointHost.UserConfig.DebugMode)
{
// View stack trace in tests and on the client
responseStatus.StackTrace = GetRequestErrorBody() + ex;
}
Log.Error("ServiceBase<TRequest>::Service Exception", ex);
//If Redis is configured, maintain rolling service error logs in Redis (an in-memory datastore)
var redisManager = TryResolve<IRedisClientsManager>();
if (redisManager != null)
{
try
{
//Get a thread-safe redis client from the client manager pool
using (var client = redisManager.GetClient())
{
//Get a client with a native interface for storing 'ResponseStatus' objects
var redis = client.GetTypedClient<ResponseStatus>();
//Store the errors in predictable Redis-named lists i.e.
//'urn:ServiceErrors:{ServiceName}' and 'urn:ServiceErrors:All'
var redisSeriviceErrorList = redis.Lists[UrnId.Create(UrnServiceErrorType, ServiceName)];
var redisCombinedErrorList = redis.Lists[UrnId.Create(UrnServiceErrorType, CombinedServiceLogId)];
//Append the error at the start of the service-specific and combined error logs.
redisSeriviceErrorList.Prepend(responseStatus);
redisCombinedErrorList.Prepend(responseStatus);
//Clip old error logs from the managed logs
const int rollingErrorCount = 1000;
redisSeriviceErrorList.Trim(0, rollingErrorCount);
redisCombinedErrorList.Trim(0, rollingErrorCount);
}
}
catch (Exception suppressRedisException)
{
Log.Error("Could not append exception to redis service error logs", suppressRedisException);
}
}
var responseDto = CreateResponseDto(request, responseStatus);
if (responseDto == null)
{
throw ex;
}
return new HttpResult(responseDto, null, HttpStatusCode.InternalServerError);
}
Otherwise for normal ASP.NET web services frameworks I would look at the Global.asax events, specifically the 'Application_BeginRequest' event which Fires each time a new request comes in.
I don't know if this is what you are looking for ,just add this to you WCF config file after the ""
It will create very extensive logging that you will be able to read using the Microsoft Service Trace Viewer
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelMessageLoggingListener">
<filter type="" />
</add>
</listeners>
</source>
<source name="System.ServiceModel" switchValue="Warning, ActivityTracing"
propagateActivity="true">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelTraceListener">
<filter type="" />
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="C:\ServiceLog.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
<add initializeData="C:\Tracelog.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
</sharedListeners>
</system.diagnostics>