This is a little complex, but I'll try and explain clearly.
I have a class library for common code components; and I tried to make some common ConfigurationHandler
base classes, to simplify creating custom configuration sections, collections and elements.
What I've ended up with is:
The ConfigurationSectionBase
class is generic, taking TConfElementCollection As {ConfigurationElementCollection, New}
as a type constraint.
This ConfigurationSectionBase
class contains a Public MustOverride Property Collection As TConfElementCollection
.
The idea is that in the project using the class library, they simply have to override the collection and decorate it with the <ConfigurationProperty("CollectionName")>
attribute, e.g:
<ConfigurationProperty("CollectionName")>
Public Overrides Property Collection As DerivedConfigurationElementCollection
Get
Return TryCast(Me("CollectionName"), DerivedConfigurationElementCollection)
End Get
Set(value As DerivedConfigurationElementCollection)
Me("CollectionName") = value
End Set
End Property
This was working fine - in the using application I could create the section, then in my config handler class I could call
Dim section As DerivedSection = (TryCast(Config.GetSection("DerivedSection"), DerivedSection))
Dim coll as DerivedConfigurationElementCollection = section?.Collection
My next thought, then, was why not abstract the Config Handler class also, and move that into a base class?
This proved more complex, but I ended up with the following code in a ConfigurationHandlerBase
class in the DLL:
Protected Function GetCollection(Of TCollection As ConfigurationElementCollection, TSection As {ConfigurationSectionBase(Of TCollection), New})(sectionName as String) As TCollection
Dim s As TSection = (TryCast(Config.GetSection(sectionName), TSection))
Return s?.Collection ' AccessViolationException is thrown on this line
To try and diagnose the problem, I made a String property in the same manner as the Collection (MustOverride
in the ConfigurationSectionBase
class in the DLL , overridden in the using application), then tried accessing that from the class library - and again, the same issue.
So I think the issue is something to do with MustOverride
and the DLL code not recognising that the Derived class has overridden the Property.
If I return the TSection
from the DLL method instead, then access the Collection
property in the application that uses the DLL; I can access the Collection fine.
The weird thing is, If I put a breakpoint in, Visual Studio will quite happily show me the contents of the Collection
property, without throwing any Exceptions.
Also, if I replace (TryCast(Config.GetSection(sectionName), TSection))
with new TSection()
, I still get an AccessViolationException - so it's nothing to do with the fact that I'm accessing the Config File, as far as I can see.
Has anyone come across this before; or what could my next steps be for troubleshooting this Exception?
You are a victim of a vb.net compiler code generation bug, it mangles the code for the ConfigurationHandlerBase.GetCollection() method. It inappropriately optimizes the property getter call for the Collection property, using a constrained call. Easiest way to see it is to run PEVerify.exe on the TestCollection.dll assembly, albeit that the error message looks misleading to me:
Searching for the error message however lands you on this github.com issue. Marked as fixed 3 months ago, I think it was this SO question that got it repaired. It isn't always obvious when such fixes make it to our machines. Not today.
The workaround proposed in the github issue does not appear to be effective. Simplest workaround I see is to avoid the elvis operator and get back to basics, rewrite:
To: