entlib:in Configuration Manager doesnt find the object

Topics: General discussion
Sep 28, 2007 at 9:50 AM
Hi every1, i'm quite newbie with entlib and i dont find what's wrong with this simple code i'm doing to start understand why a more complex application crash.
I'm using entlib 3.1 in a webapp and this is what i do:

web.config:
<?xml version="1.0"?>
<!--
Note: As an alternative to hand editing this file you can use the
web admin tool to configure settings for your application. Use
the Website->Asp.Net Configuration option in Visual Studio.
A full list of settings and comments can be found in
machine.config.comments usually located in
\Windows\Microsoft.Net\Framework\v2.x\Config
-->
<configuration>
<configSections>

<section name="enterpriseLibrary.ConfigurationSource" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationSourceSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</configSections>
<enterpriseLibrary.ConfigurationSource xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.microsoft.com/practices/enterpriselibrary/08-31-2004/configuration">
<configurationSections>
<!-- MyObj section !-->
<configurationSection name="MyObjSection">
<storageProvider xsi:type="XmlFileStorageProviderData" name="Xml File Storage Provider" path="Obj.config"/>
<dataTransformer xsi:type="XmlSerializerTransformerData" name="Xml Serializer Transformer">
<includeTypes/>
</dataTransformer>
</configurationSection>
<!-- End MyObj section -->
</configurationSections>
</enterpriseLibrary.ConfigurationSource>
<appSettings/>
<connectionStrings/>
<system.web>
<!--
Set compilation debug="true" to insert debugging
symbols into the compiled page. Because this
affects performance, set this value to true only
during development.
-->
<compilation debug="true">
<assemblies>
<add assembly="System.Management, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Configuration.Install, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Messaging, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/></assemblies></compilation>
<!--
The <authentication> section enables configuration
of the security authentication mode used by
ASP.NET to identify an incoming user.
-->
<authentication mode="Windows"/>
<!--
The <customErrors> section enables configuration
of what to do if/when an unhandled error occurs
during the execution of a request. Specifically,
it enables developers to configure html error pages
to be displayed in place of a error stack trace.

<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
</system.web>
</configuration>


Obj.config:
<?xml version="1.0" encoding="utf-8"?>
<MyObjSection>
<xmlSerializerSection type="Test.MyObj, Test">
<MyObj xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ServerName>www.w3.org</ServerName>
<ServerPort>80</ServerPort>
</MyObj>
</xmlSerializerSection>
</MyObjSection>


MyObj.cs


namespace Test
{
public class MyObj
{
public static string SectionName = "MyObjSection";
private string serverName = "Test";
private int serverPort = 80;
public string ServerName
{
get { return this.serverName; }
set { this.serverName = value; }
}
public int ServerPort
{
get { return this.serverPort; }
set { this.serverPort = value; }
}
public MyObj()
{
//
// TODO: Add constructor logic here
//
}
}
}


default.aspx

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{


Response.Write(((Test.MyObj)ConfigurationManager.GetSection("MyObjSection")).ServerName);
Response.Write(((Test.MyObj)ConfigurationManager.GetSection("MyObjSection")).ServerPort);
}

}


the problem is that in runtime configurationmanager.GetSection doenst find the value so i get a null value for "MyObjSection"

suggestions?
Sep 28, 2007 at 3:34 PM
Hi Giuseppe,

You seem to be mixing different configuration related mechanisms.

The ConfigurationManager is either .NET's own System.Configuration.ConfigurationManager or EntLib 1.x ConfigurationManager. If you're using EntLib 3.1 it will be the former, and this manager only knows about sections declared in the web.config file. Since you haven't declared such a section in the configSections element, you will get null. Then you're declaring EntLib's ConfigurationSourceSection, but then you're configuring it using the old, EntLib 1.x storage/transformer mechanism.

In order for this to work, you need to:
  • Make your configuration section into a proper .NET 2.0 System.Configuration configuration section.
  • Declare your configuration section in the standard configSections element.
  • Access your configuration section through an instance of EntLib's IConfigurationSource.

If you want to keep your configuration in a different file, you'll need to either declare a FileConfigurationSource to move all of EntLib's configuration to a different file, or use the standard configSource property when you declare the section. You can see examples of all this in the unit tests and quickstarts (particularly the configuration migration quick start).

Hope this helps,
Fernando
Sep 28, 2007 at 5:56 PM
Thanks Fernando,
i'm starting to better understand the scenario, can I ask you some more help?
Since i'm trying to use Entlib 3.1 in .NET 2.0 I changed the test project in this way

public class MyObj : ConfigurationSection
{
private ConfigurationProperty serverName;
private ConfigurationProperty serverPort;
ConfigurationProperty("ServerName")
public string ServerName
{
get { return (string)baseserverName; }
set { baseserverName = value; }
}

ConfigurationProperty("ServerPort")
public int ServerPort
{
get { return (int)baseserverPort; }
set { baseserverPort = value; }
}
public MyObj()
{
serverName = new ConfigurationProperty("ServerName", typeof(string));
serverPort = new ConfigurationProperty("ServerPort", typeof(int));
}

}


and the web.config in this way


<configSections>
<section name ="MyTest" type ="Test.MyObj"/>
</configSections>

<MyTest
ServerName = "MyProva"
ServerPort = "82"
/>


And all is gone ok but.....now next step, since the real work its a kind of more complex that only 2 properties i wonder if its possible to isolate the MyTest settings in a separate file...can you give me some idea about it? i tryed to take a look in quick start but i'm only more confused.... :(

Thanks a lot.
Sep 28, 2007 at 8:33 PM
You can follow the examples in the community content at the bottom of http://msdn2.microsoft.com/en-us/library/system.configuration.sectioninformation.configsource.aspx (under "Using with <section>"). Keep in mind this is just plain .NET 2.0 configuration; you don't need entlib for this.

You don't need to manage the configuration properties yourself in the settings class. Just adding the attributes is enough, and you can get and set the values using the property name as the index.

Regards,
Fernando
Sep 29, 2007 at 7:41 AM
THAAAANKS MAN, you best.

just a last thing...what do u mean with this:


fsimonazzi wrote:
You don't need to manage the configuration properties yourself in the settings class. Just adding the attributes is enough, and you can get and set the values using the property name as the index.


that i dont need to do all that amount of code in "MyObj.cs"? because i tryed with a "regular" class but the web.config said to me that was impossible to find the properties..i dont need to use the type ConfigurationProperty and i can use directly string and int just using on the get/set the attribute? that's it?

thanks again
Sep 29, 2007 at 6:58 PM
Hi Guiseppe,

Look a the sample code in http://msdn2.microsoft.com/en-us/library/system.configuration.configurationpropertyattribute(VS.80).aspx. Notice they don't manage the ConfigurationProperty instances; instead they just annotate the properties with attributes and set/get the values using the property name as the index.

Fernando
Sep 30, 2007 at 8:02 AM
thanks Fernardo :)
Sep 30, 2007 at 12:29 PM
emmh actually i got another newbie question:

Now I'm trying to use a custom logger (actually migration an old one) but i dont understand why I Cant see custom attributes; my config sounds like

<listeners>
<add DatabaseInstanceName="SqlLogging" StoredProcName="xxxxxxxx"
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.CustomTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
traceOutputOptions="None" type="yyyyy.zzzz.Custom, yyyyy.zzzz"
name="Custom Trace Listener" initializeData="" />



and I got my custom as derived from the CustomTraceListener:


ConfigurationElementType(typeof(CustomTraceListenerData))
public class Custom : CustomTraceListener
{

....
....
...
/// <summary>
/// Default constructor
/// </summary>
public CustomDatabaseSink(): base()
{
writeLogStoredProcName = Attributes"StoredProcName";
database = DatabaseFactory.CreateDatabase(Attributes"DatabaseInstanceName");

}

....
....
....



/// <summary>
/// Declare the supported attributes for <see cref="FormattedDatabaseTraceListener"/>
/// </summary>
protected override string[] GetSupportedAttributes()
{
return new string2 {"writeLogStoredProcName", "databaseInstanceName" };
}



but actually in the constructor it fails since doesnt find any attribute!!
what i'm missing ?
Oct 1, 2007 at 8:26 AM
Edited Oct 1, 2007 at 10:10 AM
mmm my guess:

i need to redefine the ..tracelistenerdata so i do:

ConfigurationElementType(typeof(MyTraceListenerData))
public class CustomTraceListener: CustomTraceListener
...
...

using :


Assembler(typeof(MyCustomTraceListenerAssembler))
public class MyTraceListenerData : CustomTraceListenerData
{
private ConfigurationProperty _StoredProcName ;
private ConfigurationProperty _DatabaseInstanceName;

private void MyInit()
{
_StoredProcName = new ConfigurationProperty("StoredProcName", typeof(string));
_DatabaseInstanceName = new ConfigurationProperty("DatabaseInstanceName", typeof(string));
}

public MyTraceListenerData()
: base()
{
MyInit();
}
public MyTraceListenerData(string name, Type type, string initData)
: base(name, type, initData)
{
MyInit();
}

public MyTraceListenerData(string name, string typeName, string initData, TraceOptions traceOutputOptions)
: base(name, typeName, initData, traceOutputOptions)
{
MyInit();
}
public MyTraceListenerData(string name, Type type, string initData, TraceOptions traceOutputOptions)
: base(name, type, initData, traceOutputOptions)
{
MyInit();
}


ConfigurationProperty("StoredProcName", IsRequired = true)
public string StoredProcName
{
get { return (string)base_StoredProcName; }
set { base_StoredProcName = value; }
}

ConfigurationProperty("DatabaseInstanceName", IsRequired = true)
public string FromAddress
{
get { return (string)base_DatabaseInstanceName; }
set { base_DatabaseInstanceName = value; }
}

}

but i keep having null on properties runtime... :(

Oct 1, 2007 at 1:26 PM
Hi,

Both approaches are valid. Let's make a distinction between custom as in "not provided by entlib" and custom as in "without specific configuration or design time experience". In the first case, you will create the provider class, the configuration class, the assembler to tie them together and the design time objects (nodes, design time managers, etc), while for the second definition you only need to provide the provider class and follow some conventions (i.e. annotate the class to have the custom config type for the provider hierarchy and have a specific constructor signature).

Fortunately, you can use the Application Block Factory bundled with EntLib to do the heavy lifting for you in both scenarios.

Hope this helps,
Fernando

Oct 1, 2007 at 2:45 PM
kinda...sure all you explain me is usefull but actually i cant use the block factory for reason too long to explain...then I need to understan how i can fix it in the code way...i think i done all right but I always find null in the base.attributes"name".
If you can shot me a sample of a easy and basic CustomtraceListener with a custom property I'll be really glad..i'm watching the same code since yesterday but i dont find any wrong...sigh

thanks again for your help Fernando
Oct 1, 2007 at 3:53 PM
You can take a look at the mock trace listener from the unit tests, \App Blocks\UnitTests\Logging\TraceListeners\MockCustomTraceListener.cs.

Fernando
Oct 1, 2007 at 6:10 PM
ok, but apparently i do the same and it doesnt work!!!!! i dont understand...the example you suggest is:

public class MockCustomTraceListener : CustomTraceListener
{
internal const string AttributeKey = "attribute";
internal readonly static string[] SupportedAttributes = new string[] { AttributeKey };
internal string initData;

.....
....
....
internal string Attribute
{
get { return AttributesAttributeKey; }
}

....
....
...
protected override string[] GetSupportedAttributes()
{
return SupportedAttributes;
}


well i do the same doing:

public class CustomXXXX: CustomTraceListener
{


public CustomXXXXX(): base()
{
writeLogStoredProcName = base.Attributes"StoredProcName";
database = DatabaseFactory.CreateDatabase(base.Attributes"DatabaseInstanceName");
}


....
.....
.....

protected override string[] GetSupportedAttributes()
{
return new string2 { "StoredProcName", "DatabaseInstanceName" };
}



}


but runtime it doesnt find the property....could be the problem is i'm trying to use it in the costructor??
Oct 1, 2007 at 6:19 PM
Da*n!!!!! was it...the problem is i try to use attributes in the costructor!!! and they r not available in that time!!!

Thanks again Fernando for your precious help :) hope this 3d will be usefull for some other newbie like me
Oct 2, 2007 at 12:39 PM
Hi Giuseppe,

I'm sorry, I hadn't noticed you were using the properties in the constructor. As you correctly realized, the properties are not available in the constructor.
However, the TraceListener hierarchy is the only case where this happens; all other "custom" providers get the collection of attributes as a constructor parameter. The reason for this is that this is the behavior you get when creating trace listeners using the standard system.diagnostics config.

Fernando
Jul 14, 2014 at 8:16 AM
Edited Jul 14, 2014 at 8:19 AM
I know this post is after a few years, but I don't think this part has changed in EntLib 5 or even 6.
I came across the same issue sometime back and wanted to put as much information as I have summarized.

The discussion above and the various samples over the net add a little confusion to what the correct approach is.
Basically, CustomListeners still inherit from the Enterprise Listeners and will allow properties / attributes that are pre-defined. Like somebody commented above, custom does not mean custom configuration.
However to achieve that, you can override the GetSupportedAttributes and use your custom properties. But there is a big limitation, these attributes are not initialized until the object is created, meaning they are not available in the constructor. Which means, you cannot use these for initializing your object properties or initializing your database or other stuff like that. (Which almost much makes it useless).
So, finally to be able to do that, you will need to create your own constructor overloads and custome properties that can be used there. To achieve this you have to create a custom provider, custom configuration and an assembler to tie them together. There is also a mention of being able to do this easier by using the Application Block Factory. In either cases, there aren't much documentation or examples.
Another important information is, All this is required only when you are creating custom TraceListener. The other classes in the library don't have this issue and thus just using a GetSupportedAttributes will suffice.

If anybody has updated links, documentation or information on the same or later version of Enterprise Library. Please do share.
Jul 15, 2014 at 6:05 AM
This thread is 7 years old and references 3 versions back. Not a lot has changed but there are some changes. For configuration of custom trace listeners use a *TraceListenerData class that defines the applicable configuration and can pass the relevant information into the custom trace listener. You could look at the custom trace listeners on the EntLib6 Sample Projects page

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to