Unable to use ConfigStore in an FeatureEventReceiver class

Jun 23, 2008 at 10:27 AM
Edited Jun 23, 2008 at 12:48 PM
Hi,

First of all I'd like to say that the concept of the Config Store is great=)

But...there is always a but, hehe. I've installed it and used it successfully until today when I tried to use it to read some values to be used in a FeatureEventReceiver. My solution still deploys, but I get a nasty error when I go to Solution Management in Central Administration:

MOSS : Failed to create feature receiver object from assembly "Maritech.SharePoint.Kundesider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=756fc77932274dea", type "Maritech.SharePoint.Kundesider.FeatureEventReceiver" for feature 09a6d068-c519-4817-a781-e68b9468a242: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeInitializationException: The type initializer for 'Maritech.SharePoint.Kundesider.FeatureEventReceiver' threw an exception. ---> COB.SharePoint.Utilities.InvalidConfigurationException: To use the Config Store where no SPContext is present, you must specify the URL of the parent site collection for the 'config' web in application config. If you are using the Config Store outside of your SharePoint web application e.g. a console app, your console app will require an app.config file with the required settings. The value should be stored in an appSettings key named 'ConfigSiteUrl'.
   at COB.SharePoint.Utilities.ConfigStore.getConfigSiteFromConfiguredUrl()
   at COB.SharePoint.Utilities.ConfigStore.<>c__DisplayClass1.<GetValue>b__0()
   at Microsoft.SharePoint.SPSecurity.CodeToRunElevatedWrapper(Object state)
   at Microsoft.SharePoint.SPSecurity.<>c__DisplayClass4.<RunWithElevatedPrivileges>b__2()
   at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode)
   at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(WaitCallback secureCode, Object param)
   at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(CodeToRunElevated secureCode)
   at COB.SharePoint.Utilities.ConfigStore.GetValue(String Category, String Key)
   at Maritech.SharePoint.Kundesider.FeatureEventReceiver..cctor()
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache)
   at System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at System.Activator.CreateInstance(Type type)
   at Microsoft.SharePoint.Administration.SPFeatureDefinition.get_ReceiverObject()

I've checked my web.config, and it contains the keys needed:

    <add key="ConfigListName" value="Config store" />
    <add key="ConfigSiteUrl" value="http://moss:7777" />
    <add key="ConfigWebName" value="" />

What am I doing wrong? Is there some way of manually passing the url of the SiteCollection to the ConfigStore object? This is how I use it in my code:

// Get the value of the LogFolder variable from the Config Store
private static string LogFolder = ConfigStore.GetValue(ApplicationName, "LogFolder");

Thanks in advance!
Oh and if you're still working on this project, might I recommend that you implement a AddValue method?=)


UPDATE,

I've traced the problem to the getAppSettingsValue method of the ConfigStore class. You have a try\catch clause here, but you are not doing anything in the catch block, so I added some code to print the exception to a text file, and it says "The key 'ConfigSiteUrl' does not exist in the appSettings configuration section." even though I can clearly see those sections in my web.config file as noted above... Can you reproduce this behavior? I'm assuming this is the part where it is supposed to figure out where the config list is without a Context, so it might not have been tested that much...


YET ANOTHER UPDATE,

I realize now that the getAppSettingsValue method does not look in the web.config file but in the app.config (?) file of the VS project itself, so this explains why it's not working, but it also reveals a shortcoming in the design of the Config Store. The whole idea, atleast in my mind, of using the Config Store is so that I don't hardcode any references like url's or guid's in my project, and thus I can redeploy the project to another server (with another url to the config list) without having to recompile my code. This works fine as long as there is a SPContext from which the the WebApplication object (which is needed to read from the web.config file) can be accessed. When there is no SPContext object, there is no way to figure out which WebApplication has the web.config settings needed to find the config list.

It also struck me that even though this feature is scoped for a SiteCollection, the web.config settings can only support one instance of the config list per WebApplication, as trying to activate the feature to a second SiteCollection on the same WebApplication would simply overwrite the web.config settings made when the feature was activated to the first SiteCollection...

Perhaps it would be better to have a way of creating an instance of the ConfigStore class and pass a reference to the SiteCollection in the constructor? This way I could create the ConfigStore object within one of the methods of my FeatureEventReceiver or ItemEventReceiver class and simply pass the properties.Feature.Parent property?

I'd love to hear your thoughts on this!
Coordinator
Jun 30, 2008 at 6:31 PM
DrLeary,

Sorry for not noticing this until now. Great comments, thanks for taking the time.

A couple of responses/suggestions:

- re: the issue with using in a feature receiver - sorry I didn't specifically test this scenario. The failure to read from web.config when executing within the feature framework is not to do with any config file in the VS project. I think it's because the solution is being deployed by the SP timer service, and therefore cannot 'see' the web application's config file because we're in a different context. My suggestion could be to move the config keys to your machine.config file instead, where I think they will be read successfully.
- You're right about the scoping of site collection rather than web application - the latter probably would have been a better choice, and your suggested enhancement of passing a site collection reference to the constructor is a great one I think.

Unfortunately my spare time is currently spent on developing the next version of my Content Deployment Wizard, but if you are interested in implementing your suggestion publicly I'd be happy to add you as a contributor on the project.

Let me know, and many thanks for your comments either way..
Jun 1, 2009 at 12:39 PM

I would really like to see this fixed as well.

I have the same issue where I need to read the Config Values from a Feature Receiver.

I am not convinced by adding the keys in the machine.config as I may want different Config Stores for different site collections.

I look forward to some updates.

Mark
http://sharepointstudio.com

May 7, 2012 at 2:54 PM

During feature activation, the only "config" being used is stsadm.exe.config, so if you don't put the same <appSettings> in stsadm.exe.config that you have in your web.config, any attempt to use Config Store (or anything else that uses <appSettings> values for that matter) during feature activation/deactivation, will fail.

On my Windows 2003 R2 (64-bit) MOSS 2007 SP2 (64-bit) server, stsadm.exe.config can be found here:

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\BIN\stsadm.exe.config

Yours may be somewhere else.

We also put certain <appSettings> into owstimer.exe.config as well, since some of our custom SharePoint Timer Jobs need environment-specific <appSetting> values and those jobs only read from owstimer.exe.config, not web.config.