Problem:
Recently I uploaded a ASP.NET2.0 website with a hosting provider (shared environment), and started getting this error when ever I wanted to load the providers declared on the config file:
[SecurityException: Request for the permission of type
'System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089' failed.]
System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean
isPermSet) +0
System.Security.CodeAccessPermission.Demand() +59
System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean
useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs,
String msgPath, Boolean bFromProxy) +678
System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) +114
System.Configuration.Internal.InternalConfigHost.StaticOpenStreamForRead(String streamName) +80
System.Configuration.Internal.InternalConfigHost.System.Configuration.Internal.IInternalConfigHost.Op
enStreamForRead(String streamName, Boolean assertPermissions) +115
System.Configuration.Internal.InternalConfigHost.System.Configuration.Internal.IInternalConfigHost.Op
enStreamForRead(String streamName) +7
System.Configuration.Internal.DelegatingConfigHost.OpenStreamForRead(String streamName) +10
System.Configuration.UpdateConfigHost.OpenStreamForRead(String streamName) +42
System.Configuration.BaseConfigurationRecord.InitConfigFromFile() +443
Background
To develop this site I used
- ASP.NET2.0
- MS Ajax
- .NetTiers
- SQL Server 2000
After doing further investigation by looking deep into the code and the internal exceptions:
System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean
ignoreLocal) at
System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors(ConfigurationSchemaErrors
schemaErrors) at System.Configuration.Configuration..ctor(String
locationSubPath, Type typeConfigHost, Object[]
hostInitConfigurationParams) at
System.Configuration.Internal.InternalConfigConfigurationFactory.System.Configuration.Internal.IInter
nalConfigConfigurationFactory.Create(Type
typeConfigHost, Object[] hostInitConfigurationParams) at
System.Web.Configuration.WebConfigurationHost.OpenConfiguration(WebLevel
webLevel, ConfigurationFileMap fileMap, VirtualPath path, String site,
String locationSubPath, String server, String userName, String
password, IntPtr tokenHandle) at
System.Web.Configuration.WebConfigurationManager.OpenWebConfigurationImpl(WebLevel
webLevel, ConfigurationFileMap fileMap, String path, String site,
String locationSubPath, String server, String userName, String
password, IntPtr userToken) at
System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(String
path) at Something.DataAccessLayer.DataRepository.LoadProviders() in
DataRepository.cs:line
I figured out the following line of code is failing in the DataRepository.cs of .NetTiers, where it is trying to load the Configuration Object using the System.Configuration.WebConfigurationManager.
Configuration config = System.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
In this case .Nettiers DataRepository.cs tries to loads the config and then iterates through the sections and finds the desired section by using the Object Model. Infact it tries to load all the .nettiers related providers by iterating through the config sections.
An example may be ".NetTier config section".
<configSections>
<section name="netTiersService" type="Something.DataAccessLayer.Bases.NetTiersServiceSection, Something.DataAccessLayer" allowDefinition="MachineToApplication" restartOnExternalChanges="true" />
Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</configSections>
<netTiersService defaultProvider="SqlNetTiersProvider">
<providers>
<add name="SqlNetTiersProvider" type="Something.DataAccessLayer.SqlClient.SqlNetTiersProvider, Something.DataAccessLayer.SqlClient" connectionStringName="SomethingConnectionString" useStoredProcedure="false" providerInvariantName="System.Data.SqlClient"/>
</providers>
</netTiersService>
Replicating the same error in Development Environment:
After doing a bit of googling I soon realised the above piece of code requires <trust level ="Full"/>
Probably the web hosting provider is running the application in "Medium" trust level and its causing the issue.
To successfully replicate the same error in development environment I added <trust level="Medium"> in my web.config.
<system.web>
<trust level="Medium"/>
...
</system.web>
This made life easier to solve the issue when I replicated the same error in the dev environment.
Solution
To fix the issue I used WebConfigurationManager.GetSection instead of WebConfigurationManager.OpenWebConfiguration which runs fine in the trust level "Medium". Here is the code.
ConfigurationSection ntsSection = (ConfigurationSection)WebConfigurationManager.GetSection("netTiersService");
also needed to add the requiredPermission = "false" attribute in web.config files in the section name "netTierService".
<section name="netTiersService" type="Something.DataAccessLayer.Bases.NetTiersServiceSection, Something.DataAccessLayer" allowDefinition="MachineToApplication" restartOnExternalChanges="true" requirePermission="false"/>
Conclusion
Bottom line is if we want to load the providers using the WebConfigurationManager in a medium trust mode, we need to make sure that we use "System.Configuration.WebConfigurationManager.GetSection" Method instead of "System.Configuration.WebConfigurationManager.OpenWebConfiguration" method. And make sure the section node has requiredPermission="false" defined. This should work in Medium Trust Level.