I'm creating configSections in app.config with my custom handler AbraMain.MyConfigHandler
Error:
Could not load type 'AbraMain.MyConfigHandler.ApplicationListCollection' from assembly 'System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.":"AbraMain.MyConfigHandler.ApplicationListCollection"
app.config
<configuration>
<configSections>
<section name="applicationList" type ="AbraMain.MyConfigHandler.ApplicationListCollection"/>
</configSections>
<applicationList>
<add name="Abra Backup" index="0" iconIndex="0" desc="AbraBackup"/>
<add name="Abra Backup" index="0" iconIndex="0" desc="AbraBackup"/>
</applicationList>
</configuration>
MyConfigHandler.vb
Namespace MyConfigHandler
'Desc : Individual Application configuration Class
'Handle Tag : App.config -> <applicationList> -> <add>
Public Class ApplInfoConfig
Inherits ConfigurationElement
<ConfigurationProperty("name", IsRequired:=True)> _
Public Property name() As String
Get
Return CStr(Me("name"))
End Get
Set(ByVal value As String)
Me("name") = value
End Set
End Property
<ConfigurationProperty("desc", DefaultValue:="", IsRequired:=False)> _
Public Property desc() As String
Get
Return CStr(Me("desc"))
End Get
Set(ByVal value As String)
Me("desc") = value
End Set
End Property
<ConfigurationProperty("subPath", DefaultValue:="", IsRequired:=False)> _
Public Property subPath() As String
Get
Return CStr(Me("subPath"))
End Get
Set(ByVal value As String)
Me("subPath") = value
End Set
End Property
<ConfigurationProperty("index", IsRequired:=True)> _
Public Property index() As Integer
Get
Return Me("index")
End Get
Set(ByVal value As Integer)
Me("index") = value
End Set
End Property
<ConfigurationProperty("iconIndex", DefaultValue:="0", IsRequired:=False)> _
Public Property iconIndex() As Integer
Get
Return Me("iconIndex")
End Get
Set(ByVal value As Integer)
Me("iconIndex") = value
End Set
End Property
End Class
'Desc : Collection of Individual Application configuration Class
'Handle Tag : App.config -> <applicationList>
Public Class ApplicationListCollection
Inherits ConfigurationElementCollection
Protected Overloads Overrides Function CreateNewElement() As System.Configuration.ConfigurationElement
Return New ApplInfoConfig()
End Function
Protected Overrides Function GetElementKey(ByVal element As System.Configuration.ConfigurationElement) As Object
Return CType(element, ApplInfoConfig).name()
End Function
End Class
End Namespace
It seems that the problem is in the app.config on the line where you specify the handler for your custom section:
<section name="applicationList" type ="AbraMain.MyConfigHandler.ApplicationListCollection"/>
The type declaration for your custom handler type also needs to include the assembly in which it can be found. Otherwise, it will try to find it in the default System.Configuration assembly. That is also what the error message that you got said.
So you can solve it by including the name of your assembly as well. I am assuming your assembly is named AbraMain. Then you need to change that line to:
<section name="applicationList" type ="AbraMain.MyConfigHandler.ApplicationListCollection, AbraMain"/>
However, you seem to have a second problem. For a configuration section, you need to have a handler that implements ConfigurationSection.
So you need to add a new class to do that:
Public Class ApplicationList
Inherits ConfigurationSection
' You need to do the implementation. There are plenty of
' examples available on-line.
End Class
And then point your app.config to use it:
<section name="applicationList" type ="AbraMain.MyConfigHandler.ApplicationList, AbraMain"/>
Related
I have a App.config file, where I declared a section group ListOfItems and 2 sections Item_A and Item_B:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="ListOfItems">
<section name="Item_A" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<section name="Item_B" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
</startup>
<ListOfItems>
<Item_A>
<add key="FileAddress" value="http://www.example.com/file1.xml"/>
<add key="FileType" value="xml"/>
<add key="DateFieldFormat" value="yyyy/MM/dd"/>
<add key="MainFolder" value="Folder_A"/>
<add key="OutputFolder" value="output"/>
<add key="ArchiveFolder" value="archive"/>
</Item_A>
<Item_B>
<add key="FileAddress" value="http://www.example.com/file2.txt"/>
<add key="FileType" value="txt"/>
<add key="DateFieldFormat" value="yyyy-MM-dd"/>
<add key="MainFolder" value="Folder_B"/>
<add key="OutputFolder" value="output"/>
<add key="ArchiveFolder" value="archive"/>
</Item_B>
</ListOfItems>
</configuration>
Then I defined a class with properties:
Namespace DataTypes
Friend Class ItemObject
Inherits ConfigurationSection
<ConfigurationProperty("FileAddress", DefaultValue:=Nothing, IsRequired:=True)>
Public Property FileAddressProperty As String
Get
Return CType(Me("FileAddress"), String)
End Get
Protected Friend Set(ByVal value As String)
Me("FileAddress") = value
End Set
End Property
<ConfigurationProperty("FileType", DefaultValue:="xml", IsRequired:=True)>
Public Property FileTypeProperty As String
Get
Return CType(Me("FileType"), String)
End Get
Protected Friend Set(ByVal value As String)
Me("FileType") = value
End Set
End Property
<ConfigurationProperty("DateFieldFormat", DefaultValue:="yyyy/MM/dd", IsRequired:=True)>
Public Property DateFieldFormatProperty As String
Get
Return CType(Me("DateFieldFormat"), String)
End Get
Protected Friend Set(ByVal value As String)
Me("DateFieldFormat") = value
End Set
End Property
<ConfigurationProperty("MainFolder", DefaultValue:="Folder", IsRequired:=True)>
Public Property MainFolderProperty As String
Get
Return CType(Me("MainFolder"), String)
End Get
Protected Friend Set(ByVal value As String)
Me("MainFolder") = value
End Set
End Property
<ConfigurationProperty("OutputFolder", DefaultValue:="output", IsRequired:=True)>
Public Property OutputFolderProperty As String
Get
Return CType(Me("OutputFolder"), String)
End Get
Protected Friend Set(ByVal value As String)
Me("OutputFolder") = value
End Set
End Property
<ConfigurationProperty("ArchiveFolder", DefaultValue:="archive", IsRequired:=True)>
Public Property ArchiveFolderProperty As String
Get
Return CType(Me("ArchiveFolder"), String)
End Get
Protected Friend Set(ByVal value As String)
Me("ArchiveFolder") = value
End Set
End Property
End Class
End Namespace
Now I have looked here and here, but I cannot figure out how to write the following loop:
Foreach item in ListOfItems, create an ItemObject with data from App.config (I would add it to a list of ItemObjects. So I would have a list with 2 items in it, one for Item_A and one for Item_B
OK, this worked just fine in VS 2013. It's only when I started work anew on the project after my upgrade to 2015 that the problem has showed up.
In a nutshell, I'm unsure how to tell the WCF Proxy Generator to specify a CLR namespace for a property type; apparently this is required now.
Here's my contract:
<ServiceContract>
Friend Interface IService
<OperationContract> Function CheckFiles() As List(Of String)
<OperationContract> Function CreateBackup(AllFiles As List(Of String)) As BackupResult
End Interface
Here's the class being returned:
Public Class BackupResult
Public Property DbService As New DbService
Public Property TmpFolder As System.IO.DirectoryInfo ' <== Problem here '
Public Property Chunks As Integer
End Class
And just for clarity, here's the class for the DbService property (although its only relevance for this question is to show that it doesn't have any System.IO references).
Public Class DbService
Public Property ErrorMessage As String = String.Empty
Public Property HasError As Boolean = False
End Class
My problem is that the proxy generator doesn't seem to be able to see that DirectoryInfo is in the System.IO namespace—it keeps generating it in the service's namespace. (When I comment out the CreateBackup() function, rerun the service and update the reference, the QbBackup.DirectoryInfo class isn't generated. I don't get the warning shown below and everything works—like it did in 2013—but of course without the property I need.)
Here's the generated code:
Namespace QbServer
' ... '
' '
' Other generated code here '
' '
' ... '
' '
' Note the generated DirectoryInfo class and '
' the BackupResult.TmpFolder property of type '
' QbServer.DirectoryInfo, when the namespace '
' should be System.IO instead '
' '
<System.Diagnostics.DebuggerStepThroughAttribute(),
System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0"),
System.Runtime.Serialization.DataContractAttribute(Name:="BackupResult", [Namespace]:="http://schemas.datacontract.org/2004/07/Service"),
System.SerializableAttribute()>
Partial Public Class BackupResult
Inherits Object
Implements System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged
<System.NonSerializedAttribute()>
Private extensionDataField As System.Runtime.Serialization.ExtensionDataObject
<System.Runtime.Serialization.OptionalFieldAttribute()>
Private ChunksField As Integer
<System.Runtime.Serialization.OptionalFieldAttribute()>
Private DbServiceField As QbServer.DbService
<System.Runtime.Serialization.OptionalFieldAttribute()>
Private TmpFolderField As QbServer.DirectoryInfo
<Global.System.ComponentModel.BrowsableAttribute(False)>
Public Property ExtensionData() As System.Runtime.Serialization.ExtensionDataObject Implements System.Runtime.Serialization.IExtensibleDataObject.ExtensionData
Get
Return Me.extensionDataField
End Get
Set
Me.extensionDataField = Value
End Set
End Property
<System.Runtime.Serialization.DataMemberAttribute()>
Public Property Chunks() As Integer
Get
Return Me.ChunksField
End Get
Set
If (Me.ChunksField.Equals(Value) <> True) Then
Me.ChunksField = Value
Me.RaisePropertyChanged("Chunks")
End If
End Set
End Property
<System.Runtime.Serialization.DataMemberAttribute()>
Public Property DbService() As QbServer.DbService
Get
Return Me.DbServiceField
End Get
Set
If (Object.ReferenceEquals(Me.DbServiceField, Value) <> True) Then
Me.DbServiceField = Value
Me.RaisePropertyChanged("DbService")
End If
End Set
End Property
<System.Runtime.Serialization.DataMemberAttribute()>
Public Property TmpFolder() As QbServer.DirectoryInfo
Get
Return Me.TmpFolderField
End Get
Set
If (Object.ReferenceEquals(Me.TmpFolderField, Value) <> True) Then
Me.TmpFolderField = Value
Me.RaisePropertyChanged("TmpFolder")
End If
End Set
End Property
Public Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Protected Sub RaisePropertyChanged(ByVal propertyName As String)
Dim propertyChanged As System.ComponentModel.PropertyChangedEventHandler = Me.PropertyChangedEvent
If (Not (propertyChanged) Is Nothing) Then
propertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(propertyName))
End If
End Sub
End Class
<System.Diagnostics.DebuggerStepThroughAttribute(),
System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")>
Public Class DirectoryInfo
End Class
End Namespace
And here's the warning I'm getting in Visual Studio 2015:
Custom tool warning: Cannot import wsdl:portType
Detail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporter
Error: ISerializable type with data contract name 'DirectoryInfo' in namespace 'http://schemas.datacontract.org/2004/07/System.IO' cannot be imported. The data contract namespace cannot be customized for ISerializable types and the generated namespace 'QbServer' does not match the required CLR namespace 'System.IO'. Check if the required namespace has been mapped to a different data contract namespace and consider mapping it explicitly using the namespaces collection.
XPath to Error Source: //wsdl:definitions[#targetNamespace='http://tempuri.org/']/wsdl:portType[#name='IService'] ConsoleTest D:\Dev\Customers\OIT\Active\ConsoleTest\Service References\QbServer\Reference.svcmap 1
This all results in the proxy classes not being generated.
I've been reading this and this, but they seem to pertain to custom namespaces at the service level. I need to know how to tell the generator to recognize the property type as a CLR type and NOT generate a DirectoryInfo class of its own.
The class System.IO.DirectoryInfo is not supported by the DataContractSerializer. Instead you could try using the XmlSerializer, but you'll likely run into other issues.
A simple solution is to add a string property which captures the data needed to recreate the correct objects. You can keep the original property as well, just be sure to mark it with the [NonSerialized] attribute.
Alternatively you can use the OnSerializing and OnDeserializing attributes to ensure that the DirectoryInfo value is stored in the string field and so that the DirectoryInfo is restored after deserialization.
For more information see:
https://blogs.msdn.microsoft.com/carlosfigueira/2011/09/05/wcf-extensibility-serialization-callbacks/
I have a POCO object and I want to mark a property as a key (see TestClass below).
I'm getting the following error.
'Key' cannot be used as an attribute because it is not a class. C:\Users\zzz\Documents\Visual Studio 2010\Projects\zzz\zzz\BO\TestClass.vb
Public Class TestClass
<Key()>
Private _TestIdentifier As String
Public Property TestIdentifier() As String
Get
Return _TestIdentifier
End Get
Set(ByVal value As String)
_TestIdentifier = value
' Me.NotifyPropertyChanged("TestIdentifier")
End Set
End Property
End Class
I had a missing import and reference
Imports System.ComponentModel.DataAnnotations
And reference System.ComponentModel.DataAnnotations.dll
I have the following class which I want to serialize to XML:
<Serializable()> _
Public Class Settings
Public Shared var1 As Boolean = False
Public var2 As Boolean = False
End Class
I create a new instance and serialize it using my own method...
SaveSerialXML(PathToFile, New Settings, GetType(Settings))
...however the shared (static) variable is not included in the output:
<?xml version="1.0" encoding="utf-8"?>
<Settings>
<var2>false</var2>
</Settings>
Does anyone know of a way to serialize shared members of a class to XML?
Serialization is about serializing instances. Shared variables do not belong to an instance.
You can cheat add a redirect instance property for serialization.
For example:
Public Property Var1Instance As Boolean
Get
Return Var1
End Get
Set(value As Boolean)
Var1 = value
End Set
End Property
I've often found myself wanting to implement my own Xml serialization and not use the .NET XmlSerializer.
I do so by adding an Xml property to my class that directly handles the serialization via Xml Literals. That property could be a String or an XElement depending on how I'm going to use it.
Here's how the Xml String property would look for your sample class:
Public Property Xml() As String
Get
Return <Settings>
<var1><%= var1 %></var1>
<var2><%= var2 %></var2>
</Settings>.ToString
End Get
Set(ByVal value As String)
Dim xValue = XElement.Parse(value)
var1 = xValue...<var1>.Value = "true"
var2 = xValue...<var2>.Value = "true"
End Set
End Property
This places all the serialization logic in one place and avoids the use of attributes to control how an instance gets serialized. The other benefit I've found is that this allows me to deserialize a class that does not have a default constructor.
In production scenarios I would add an extension method that converts a String to a Boolean instead of comparing to "true" since valid Xml Boolean values include true, false, 1 and 0.
I have a simple class that I trying to populate from an XML document.
The XML file has an attribute called TrackingID in the root node which I would like to get as a property. For some reason, when I deseralize the class, the TrackingID is null. Everything else populates fine. I have tried various attributes on the TrackingID property with no luck.
Any ideas?
Code:
Dim faultXML As String = "<?xml version='1.0' encoding='UTF-8' ?>"
faultXML += "<myxmlns:Fault xmlns:myxmlns='http://somename/space' xmlns:myxmlns_base=http://somename/base' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://somename/space
faultXML += "myxmlns_102809.xsd http://idealliance.org/maildat/Specs/md091/myxmlns70C/base myxmlns_base_102809.xsd' myxmlns:TrackingID='160217057912'>"
faultXML += "<myxmlns:FaultCode>500</myxmlns:FaultCode>"
faultXML += "<myxmlns:FaultDescription>Some Description.</myxmlns:FaultDescription>"
faultXML += "</myxmlns:Fault>"
Dim fault As WebServiceFault
Dim Serializer As New XmlSerializer(GetType(WebServiceFault))
Using sr As New System.IO.StringReader(faultXML)
fault = DirectCast(Serializer.Deserialize(sr), WebServiceFault)
End Using
Class:
Imports System.Xml.Serialization
<System.SerializableAttribute(), _
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True, [Namespace]:="http://somename/space"), _
System.Xml.Serialization.XmlRootAttribute([ElementName]:="Fault", [Namespace]:="http://somename/space", IsNullable:=False)> _
Public Class WebServiceFault
Private faultCodeField As String
Private faultDescriptionField As String
Private trackingIDField As String
Public Property FaultCode() As String
Get
Return Me.faultCodeField
End Get
Set(ByVal value As String)
Me.faultCodeField = value
End Set
End Property
Public Property FaultDescription() As String
Get
Return Me.faultDescriptionField
End Get
Set(ByVal value As String)
Me.faultDescriptionField = value
End Set
End Property
Public Property TrackingID() As String
Get
Return Me.trackingIDField
End Get
Set(ByVal value As String)
Me.trackingIDField = value
End Set
End Property
End Class
I was able to find an answer. Adding the below attribute solved my problem.
<System.Xml.Serialization.XmlAttributeAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Qualified)> _
Public Property TrackingID() As String
Get
Return Me.trackingIDField
End Get
Set(ByVal value As String)
Me.trackingIDField = value
End Set
End Property