Dynamic Exception Messages

Topics: Building and extending application blocks, Exception Handling Application Block
May 11, 2010 at 7:30 AM

Is there any way that I can create a user friendly message dynamically, using string.Format? I want to be able to populate the message with properties of the current object, is this possible?

May 11, 2010 at 7:43 AM

Why not? What are the things you think which makes this a problem?   

By the way, is this question concerned on how to do this in entlib's exception handling block

 

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

May 11, 2010 at 7:58 AM
Edited May 11, 2010 at 8:01 AM

From the 4.1 API, it looks to me like the exception messages are formatted at compile time.

May 11, 2010 at 8:10 AM

I think you can achieve what you want by creating a custom exception handler.  The custom exception handler includes code for constructing the user-friendly message you want and assign that as the message for the new exception that your handler returns. 

 

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

May 11, 2010 at 8:27 AM

With custom handlers I need to know which object will be throwing the exception. With several different objects in my app, that would require me to write the same number of overwrites of the TextExceptionFormatter just to change the parameters of the string formatter. What I want is to be able to paas the formatted string locally, different for each catch block.

May 11, 2010 at 1:15 PM

OK, just realized I was reading the wrong section of the API. My appologies.

May 12, 2010 at 10:29 AM
Edited May 12, 2010 at 10:41 AM

So I have authored the custom exception formatter and exception handler, but because of the bug in the TypeSelector, I couldn't load it. I tried working around this by manually editing the web.config:

 

<exceptionHandlers >

<add exceptionMessage="Cannot retrieve the information" exceptionMessageResourceName="" 

 exceptionMessageResourceType="" type="CMPExceptionLibrary.CMPExceptionHandler, CMPExceptionLibrary.dll"

</exceptionHandlers >

name="CMPHandler" />

 

but then got the following exception:

Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionHandlingException was unhandled by user code
  Message="The current build operation (build key Build Key[Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicyImpl, DatabaseRead]) failed: The type 'CMPExceptionLibrary.CMPExceptionHandler, CMPExceptionLibrary.dll' cannot be resolved. Please verify the spelling is correct or that the full type name is provided. (Strategy type ConfiguredObjectStrategy, index 2)"
  Source="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
  StackTrace:
       at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy.GetExceptionPolicy(Exception exception, String policyName, ExceptionPolicyFactory factory)
       at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy.HandleException(Exception exceptionToHandle, String policyName, ExceptionPolicyFactory policyFactory)
       at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy.HandleException(Exception exceptionToHandle, String policyName)
       at CMPExceptionLibrary.ExceptionManagement.ExceptionProcessor(Exception ex, String policy) in D:\Ivan\Documents\Visual Studio 2008\Projects\TrialApp\CMPExceptionLibrary\ExceptionManagement.cs:line 146
       at ReadWriteApp.ControlPage.Read_Click(Object sender, EventArgs e) in D:\Ivan\Documents\Visual Studio 2008\Projects\ReadWriteWebService\ReadWriteApp\ControlPage.aspx.cs:line 31
       at System.Web.UI.WebControls.Button.OnClick(EventArgs e)
       at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
       at System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
       at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)
       at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)
       at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
  InnerException: Microsoft.Practices.ObjectBuilder2.BuildFailedException
       Message="The current build operation (build key Build Key[Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicyImpl, DatabaseRead]) failed: The type 'CMPExceptionLibrary.CMPExceptionHandler, CMPExceptionLibrary.dll' cannot be resolved. Please verify the spelling is correct or that the full type name is provided. (Strategy type ConfiguredObjectStrategy, index 2)"
       Source="Microsoft.Practices.ObjectBuilder2"
       BuildKey="Build Key[Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicyImpl, DatabaseRead]"
       ExecutingStrategyIndex=2
       ExecutingStrategyTypeName="ConfiguredObjectStrategy"
       StackTrace:
            at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
            at Microsoft.Practices.ObjectBuilder2.Builder.BuildUp(IReadWriteLocator locator, ILifetimeContainer lifetime, IPolicyList policies, IStrategyChain strategies, Object buildKey, Object existing)
            at Microsoft.Practices.ObjectBuilder2.Builder.BuildUp[TTypeToBuild](IReadWriteLocator locator, ILifetimeContainer lifetime, IPolicyList policies, IStrategyChain strategies, Object buildKey, Object existing)
            at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.EnterpriseLibraryFactory.BuildUp[T](IReadWriteLocator locator, ILifetimeContainer lifetimeContainer, String id, IConfigurationSource configurationSource)
            at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.LocatorNameTypeFactoryBase`1.Create(String name)
            at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy.GetExceptionPolicy(Exception exception, String policyName, ExceptionPolicyFactory factory)
       InnerException: System.ArgumentException
            Message="The type 'CMPExceptionLibrary.CMPExceptionHandler, CMPExceptionLibrary.dll' cannot be resolved. Please verify the spelling is correct or that the full type name is provided."
            Source="Microsoft.Practices.EnterpriseLibrary.Common"
            StackTrace:
                 at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.AssemblyQualifiedTypeNameConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
                 at System.ComponentModel.TypeConverter.ConvertFrom(Object value)
                 at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.NameTypeConfigurationElement.get_Type()
                 at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.CustomProviderAssembler`3.Assemble(IBuilderContext context, TConfiguration objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
                 at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.AssemblerBasedObjectFactory`2.Create(IBuilderContext context, TConfiguration objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
                 at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicyEntryCustomFactory.Create(IBuilderContext context, ExceptionTypeData objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
                 at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicyCustomFactory.CreateObject(IBuilderContext context, String name, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
                 at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.ConfiguredObjectStrategy.PreBuildUp(IBuilderContext context)
                 at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
            InnerException:

 

What do I do now?

May 12, 2010 at 10:46 AM

What bug of the TypeSelector are you referring to?

You shouldn't be including the .dll extension when specifying the custom handler's type.  It should be namespace.classname, assemblyname -> CMPExceptionLibrary.CMPExceptionHandler, CMPExceptionLibrary.

 

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

May 12, 2010 at 10:54 AM

The TypeSelector bug: http://entlib.codeplex.com/Thread/View.aspx?ThreadId=40626

I tried removing the .dll and it seems to have accomplished something. Now the exception is:

Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionHandlingException was unhandled by user code
  Message="The current build operation (build key Build Key[Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicyImpl, DatabaseRead]) failed: Constructor on type 'CMPExceptionLibrary.CMPExceptionHandler' not found. (Strategy type ConfiguredObjectStrategy, index 2)"
  Source="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
  StackTrace:
       at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy.GetExceptionPolicy(Exception exception, String policyName, ExceptionPolicyFactory factory)
       at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy.HandleException(Exception exceptionToHandle, String policyName, ExceptionPolicyFactory policyFactory)
       at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy.HandleException(Exception exceptionToHandle, String policyName)
       at CMPExceptionLibrary.ExceptionManagement.ExceptionProcessor(Exception ex, String policy) in D:\Ivan\Documents\Visual Studio 2008\Projects\TrialApp\CMPExceptionLibrary\ExceptionManagement.cs:line 146
       at ReadWriteApp.ControlPage.Read_Click(Object sender, EventArgs e) in D:\Ivan\Documents\Visual Studio 2008\Projects\ReadWriteWebService\ReadWriteApp\ControlPage.aspx.cs:line 31
       at System.Web.UI.WebControls.Button.OnClick(EventArgs e)
       at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
       at System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
       at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)
       at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)
       at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
  InnerException: Microsoft.Practices.ObjectBuilder2.BuildFailedException
       Message="The current build operation (build key Build Key[Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicyImpl, DatabaseRead]) failed: Constructor on type 'CMPExceptionLibrary.CMPExceptionHandler' not found. (Strategy type ConfiguredObjectStrategy, index 2)"
       Source="Microsoft.Practices.ObjectBuilder2"
       BuildKey="Build Key[Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicyImpl, DatabaseRead]"
       ExecutingStrategyIndex=2
       ExecutingStrategyTypeName="ConfiguredObjectStrategy"
       StackTrace:
            at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
            at Microsoft.Practices.ObjectBuilder2.Builder.BuildUp(IReadWriteLocator locator, ILifetimeContainer lifetime, IPolicyList policies, IStrategyChain strategies, Object buildKey, Object existing)
            at Microsoft.Practices.ObjectBuilder2.Builder.BuildUp[TTypeToBuild](IReadWriteLocator locator, ILifetimeContainer lifetime, IPolicyList policies, IStrategyChain strategies, Object buildKey, Object existing)
            at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.EnterpriseLibraryFactory.BuildUp[T](IReadWriteLocator locator, ILifetimeContainer lifetimeContainer, String id, IConfigurationSource configurationSource)
            at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.LocatorNameTypeFactoryBase`1.Create(String name)
            at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy.GetExceptionPolicy(Exception exception, String policyName, ExceptionPolicyFactory factory)
       InnerException: System.MissingMethodException
            Message="Constructor on type 'CMPExceptionLibrary.CMPExceptionHandler' not found."
            Source="mscorlib"
            StackTrace:
                 at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
                 at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
                 at System.Activator.CreateInstance(Type type, Object[] args)
                 at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.CustomProviderAssembler`3.Assemble(IBuilderContext context, TConfiguration objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
                 at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.AssemblerBasedObjectFactory`2.Create(IBuilderContext context, TConfiguration objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
                 at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicyEntryCustomFactory.Create(IBuilderContext context, ExceptionTypeData objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
                 at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicyCustomFactory.CreateObject(IBuilderContext context, String name, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
                 at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.ConfiguredObjectStrategy.PreBuildUp(IBuilderContext context)
                 at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
            InnerException:

May 12, 2010 at 11:10 AM

You should add a constructor to your custom exception handler that takes a NameValueCollection parameter

public CMPExceptionHandler(NameValueCollection attributes)

{

}

 

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

May 12, 2010 at 11:11 AM
Edited May 12, 2010 at 12:47 PM

I haven't provided a custom constructor or overwriten the default one for the handler, should I have done so?

edit: did't see the reply. I added the constructor and it seems to have solved the problem.

May 12, 2010 at 11:18 AM

The constructor which takes the NameValueCollection parameter is required because unity uses this constructor to create the instance of your custom exception handler.   It's also useful if ever you're going to need to pass some data to your custom handler which you don't want to hard-code.  You only need to add items in the Attributes property (available in the configuration tool) of your custom handler to do that and access those values in the NameValueCollection parameter.

 

rah Urmeneta
Global Technology & Solutions
Avanade, Inc.
entlib.support@Avanade.com

May 13, 2010 at 5:23 AM

I'm looking at this collection now. Can I use it to pass values that are not known at compile time, like say the name of the user currently logged on the application?

May 13, 2010 at 5:27 AM

No, those values are coming from what you specified in the config.  Not unless you have a means of determining runtime values based on them.

 

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

May 13, 2010 at 5:34 AM

Then there seems to be no way I can pass a runtime value to the handling method so it can be used to construct the exception message. Or am I missing something?

May 13, 2010 at 5:45 AM

An Exception object has its .Data collection property, you might want to use it.  Its content can also be part of the message that will be logged through the {dictionary({key} - {value} token which is by default, if you don't change the Template of your formatter, is included. 

 

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

May 13, 2010 at 6:11 AM
Edited May 13, 2010 at 6:13 AM

Thanks for the advice, but that's not what I want the users to see. Guess soft coded messages will have to do.

May 13, 2010 at 6:14 AM

Yup, that was just an fyi.

 

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