Ent Lib 3.1 Exception Handling for a WCF Service

Topics: Exception Handling Application Block
Nov 4, 2010 at 8:11 AM
Edited Nov 4, 2010 at 8:14 AM

Hi Team,

I have created a new WCF application for my projet.  I am using the Fault Contract in the WCF service to throw the custom exception back to the client. At the same time Before throwing the exception to the client, i need to log my exception in the server event log too. I have written the following piece of code for doing this. If any experts can take a look and tell me whether i am doing this in a correct way or i need to explicitly configure the Logging application block for doing this.



[DataContract]
    [ConfigurationElementType(typeof(CustomHandlerData))]
    public class ServiceFault : IExceptionHandler
    {
        public ServiceFault() { }

        public ServiceFault(NameValueCollection collection)
        {}
        [DataMember]
        public string Message { get; set; }

        [DataMember]
        public Guid Id { get; set; }

        #region IExceptionHandler Members

        public Exception HandleException(Exception exception, Guid handlingInstanceId)
        {
            return exception;
        }

        #endregion

        #region Utiliy Method

        public void HandleException(string message)
        {
            try
            {

// Is there any need of Calling the ExceptionPolicy.HandleException() method here?
                EventLog log = new EventLog("Application");
                log.Source = "TestCenter";
                if (!EventLog.SourceExists("TestCenter"))
                    EventLog.CreateEventSource(log.Source, "APplication");
                log.WriteEntry(message, EventLogEntryType.Error);
                log.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

Service implementation

 public System.Data.DataSet GetData(string securitykey, string connectText)
        {
            CheckSecurityKey(securitykey, APPSETTINGKEY);
            ConfigData config = ReadConfig();
            try
            {
                return TestManager.GetData(connectText, config.GetProcName, config.PrimaryKey);
            }
            catch (Exception ex)
            {
                ServiceFault fault = new ServiceFault { Id = Guid.NewGuid(), Message ="Error in Retrieving Data From DB" };
                fault.HandleException( ex.Message + " : Error in Retrieving Data From DB");
                throw new FaultException<ServiceFault>(fault, new FaultReason("DataBase Exception"));
            }

 <exceptionHandling>
      <exceptionPolicies>
          <add name="Global Policy">
              <exceptionTypes>
                  <add name="Exception" type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="NotifyRethrow">
                      <exceptionHandlers>
                          <add type="Test.Services.TestCenter.ServiceFault, Test.Services.TestCenter" name="Custom Handler" />
                      </exceptionHandlers>
                  </add>
              </exceptionTypes>
          </add>
      </exceptionPolicies>
  </exceptionHandling>

Is this implementation correct? Or the postHandling Action need to be changed to ThrowNewException? And do i need to call the ExceptionPolicy.HandleException(ex,"Global Policy") in my utility method HandleException(string message) ?

Thanks

TutuMon

 

Nov 4, 2010 at 8:18 AM

You need not create your own IExceptionHandler nor explicitly add codes which throws a FaultException<ServiceFault>.  These could all be achieved using the Logging Exception Handler and the Fault Contract Exception Handler.  Have you tried using the Logging Application Block?  It already has a Formatted Event Log Trace Listener which allows you to log to the event log so you need not use the Event Log API.  Check it out in the documentation.  On wrapping your exception with a FaultException<ServiceFault>, this is basically what exception shielding is about so I suggest looking at this blog on how to implement it using the Exception Handling Block. 

Let me know if anything is unclear.

 

Sarah Urmeneta
Global Technologies & Solutions
Avanade, Inc.
entlib.support@avanade.com

Nov 4, 2010 at 9:02 AM

Yeah.. Thanks. I has see that post. When i tried to add a new faultContractType as handler, i got an error saying the FaultContract is create with newer version of the damework. Since i am using the .Net Framework 4.0, i have created a new project that targets the version 3.5. And added the new types. But i have question here. Is there any change needed the service implementation part?

 public System.Data.DataSet GetData(string securitykey, string connectText)
        {
            CheckSecurityKey(securitykey, APPSETTINGKEY);
            ConfigData config = ReadConfig();
            try
            {
                return TestManager.GetData(connectText, config.GetProcName, config.PrimaryKey);
            }
            catch (Exception ex)
            {
                ServiceFault fault = new ServiceFault { Id = Guid.NewGuid(), Message ="Error in Retrieving Data From DB" };
                fault.HandleException( ex.Message + " : Error in Retrieving Data From DB");
                throw new FaultException<ServiceFault>(fault, new FaultReason("DataBase Exception"));
            }

Here i don't need to throw the fault exception?

Nov 4, 2010 at 9:08 AM

Yes, you don't need to throw a FaultException, you don't even have to put a try catch block as long as you added the ExceptionShielding attribute in your service's interface.  Your exception will automatically be replaced by an instance of FaultException<ServiceFault> assuming you got the configuration right.

 

Sarah Urmeneta
Global Technologies & Solutions
Avanade, Inc.
entlib.support@avanade.com

Nov 4, 2010 at 9:50 AM
Edited Nov 4, 2010 at 10:22 AM

Hi Sarah

Thanks a lot for the quick response. But i have one more question. The previously given GetData method is a WCF method. So i will not put a try catch on that. But i have some private helper methods and private properties in the service. That aslo doesn't have to be kept inside the try/catch block with this kind of implementation?



 public static void CheckSecurityKey(string key, string appSettingKey)
        {
            string matchKey = ConfigurationManager.AppSettings[appSettingKey];
            if (matchKey == null)
                throw new FaultException<ServiceFault>(new ServiceFault { Id = Guid.NewGuid(), Message = "Security Key Missing from Service" },new FaultReason("Missing Key"));

            if (!key.Equals(matchKey))
                throw new FaultException<ServiceFault>(new ServiceFault { Id = Guid.NewGuid(), Message = "Invalid security key supplied to Service" }, new FaultReason("No Matching Key"));
        }

AND

 public List<string> RetrieveEmail(XmlNode node)
        {
            List<string> emailList = null;
            try
            {
                if (node != null)
                {
                    emailList = new List<string>();
                    foreach (XmlElement element in node)
                    {
                        if (element.InnerText != null)
                            emailList.Add(element.InnerText);
                    }
                }
                return emailList;
            }
            catch (Exception ex)
            {
                ServiceFault fault = new ServiceFault { Id = Guid.NewGuid(), Message = "Error in Reading the EmailList" };
                fault.HandleException(ex.Message + " : Error in Reading the EmailList");
                throw new FaultException<ServiceFault>(fault, new FaultReason("Error : EmailList"));
            }

Thanks

Tutu

Nov 5, 2010 at 1:27 AM

Yes, you don't have to put try catch blocks even in private methods.  Although I'm still wondering why your code still shows try catch blocks and explicitly throwing FaultExceptions.

 

Sarah Urmeneta
Global Technologies & Solutions
Avanade, Inc.
entlib.support@avanade.com