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
Related
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'm trying to teach myself reflection and have been googling but I can't wrap my head around it entirely. I created a class called DataClass which contains a method called GetClassFromDB as you can see below, which will be inherited from multiple classes.
What I am attempting to do is have my dataclass read the TableName property that is defined within objResults. Once I pull in the tablename from objResults I would query the SQL database for a dataset. Once I have the dataset I would create a new object of the same TYPE inheriting this class (Which will be different types) and populate it from the dataset. Once I have the newly populated class I will return it for use.
I believe I have gotten most of the way there properly (Please correct me if there is a better way), but my real question is this. How can I create a new class of the type thats deriving that class from that string name that I getting in my code, or the type. I would want to have all the accessible properties from objResults available.
Namespace MyApp
Public Class DataClass
Private _TableName As String
Private _Name As String
Overridable ReadOnly Property TableName As String
Get
Return _TableName
End Get
End Property
Public Overloads Function GetClassFromDB() As Object
Try
Dim BaseObject As New Object
'Get the object name
Dim objName As String = MyBase.GetType().Name
'Gets the type thats calling this method
Dim objDerived As Type = MyBase.GetType()
'Get the property info to request the tablename from the derived class
Dim TableName As PropertyInfo = objDerived.GetProperty("TableName")
Dim TableNameString As String = TableName.GetValue(Me, Nothing).ToString
'Once I get the table name from objResults I can perform the SQL
Dim QueryResults as DataSet = SQLiteCLass.Query("Select * FROM TableNameString")
'Once I get data from the SQL I want to create a new object of the type deriving this method.
'In this example is objResults
Dim NewObject as objDerived
'Now I can fill my new object with the results and return it as an object
'THIS IS MY QUESTION - How can I create a new object of the TYPE that I receive from Reflection
Return False
Catch ex As Exception
Return False
End Try
End Function
End Class
End Namespace
and this is a sample class that would inherit my dataclass.
Public Class objResults
Inherits MyApp.DataClass
Private _GameID As Guid
Public Property GameID As Guid
Get
Return _GameID
End Get
Set(ByVal value As Guid)
_GameID = value
End Set
End Property
Public Overrides ReadOnly Property TableName As String
Get
Return "This is my tablename"
End Get
End Property
End Class
and this is how I would use this in code.
Dim objResult as New objResults
Dim TodaysResult as objResultsCollection
TodaysResult = objResult.GetClassFromDB()
I have a set of classes, whose properties have data annotations on them. Some of these class properties are of primitive types (and by primitive, I also mean types such as string, double, datetime etc), while others are properties of a custom type.
I would like to be able to iterate through the properties of a class and the properties of the nested objects and pull out the attributes of each property. I’ve played around with reflection and my code works fine, if the class under consideration has only one property of a custom type.
However when a class has multiple properties of a custom type and each of those properties have other custom types, I am completely lost on how I’d keep track of the objects/properties that have already been visited.
This is where I have got so far. I have seen a lot of examples on the forum, but they all have a simple nested class, where there is a maximum of one custom type per class.
Below is a sample of what I am trying to get done:
Public Class Claim
<Required()>
<StringLength(5)>
Public Property ClaimNumber As String
<Required()>
Public Property Patient As Patient
<Required()>
Public Property Invoice As Invoice
End Class
Public Class Patient
<Required()>
<StringLength(5)>
Public Property MedicareNumber As String
<Required()>
Public Property Name As String
<Required()>
Public Property Address As Address
End Class
Public Class Address
Public Property Suburb As String
Public Property City As String
End Class
Public Class Invoice
<Required()>
Public Property InvoiceNumber As String
<Required()>
Public Property Procedure As String
End Class
Public Shared Function Validate(ByVal ObjectToValidate As Object) As List(Of String)
Dim ErrorList As New List(Of String)
If ObjectToValidate IsNot Nothing Then
Dim Properties() As PropertyInfo = ObjectToValidate.GetType().GetProperties()
For Each ClassProperty As PropertyInfo In Properties
Select Case ClassProperty.PropertyType.FullName.Split(".")(0)
Case "System"
Dim attributes() As ValidationAttribute = ClassProperty.GetCustomAttributes(GetType(ValidationAttribute), False)
For Each Attribute As ValidationAttribute In attributes
If Not Attribute.IsValid(ClassProperty.GetValue(ObjectToValidate, Nothing)) Then
ErrorList.Add("Attribute Error Message")
End If
Next
Case Else
Validate(ClassProperty.GetValue(ObjectToValidate, Nothing))
**** ‘At this point I need a mechanism to keep track of the parent of ClassProperty and also mark ClassProperty as visited, so that I am able to iterate through the other properties of the parent (ObjectToValidate), without revisiting ClassProperty again.**
End Select
Next
End If
Return Nothing
End Function
The most straightforward (and probably easiest) way to approach this is to keep a Dictionary of class property attributes keyed by class name.
If I were approaching this, I would probably create a class to hold the property attributes:
Public Class PropertyAttribute
Public PropertyName As String
Public PropertyTypeName As String
Public Required As Boolean
Public StringLength As Integer
End Class
Then create a class to hold information about each class' properties:
Public Class ClassAttributes
Public ClassName As String
' You could also use a dictionary here to key properties by name
Public PropertyAttributes As New List(Of PropertyAttribute)
End Class
Finally, create a dictionary of ClassAttributes to keep track of which custom classes you have already processed:
Public ProcessedClasses As New Dictonary(Of String, ClassAttributes)
The key for the dictionary is the classname.
When you are processing the attributes through reflection, if the property type is custom, check the dictionary for the existence of the class. If it is there, you don't have to process it.
If it is not there, add a new instance to the dictionary immediately (so that nested objects of the same type are safely handled) and then process the attributes of the class.
I have a class created from an XSD file in vb.net2010
Partial Public Class responseOperation
Private attributeField() As attribute
Public Property attribute() As attribute()
Get
Return Me.attributeField
End Get
Set(ByVal value As attribute())
Me.attributeField = value
End Set
End Property
how do i instantiate or fill up attribute property where attribute class is given as
Partial Public Class attribute
Private nameField As String
Private valueField As String
Public Property name() As String
Get
Return Me.nameField
End Get
Set(ByVal value As String)
Me.nameField = value
End Set
End Property
Public Property value() As String
Get
Return Me.valueField
End Get
Set(ByVal value As String)
Me.valueField = value
End Set
End Property
End Class
when i run
xml_req_obj.attribute(0).value = "abcd"
xml_req_obj.attribute(0).name = "efg"
I get runtime error as im assigning something to a class that is not created
This seems like a trivial task
If some can tell me how can I create this object and pass data to attribute property that would be wonderful
Thankyou
Hansen
You are not instantiating the array or array items.
Try
Private attributeField() As attribute = New attribute(20)
and
xml_req_obj.attribute(0) = New Attribute()
xml_req_obj.attribute(0).value = "abcd"
xml_req_obj.attribute(0).name = "efg"
I've attempted to create an abstracted control to manage some of the state in our application. However, I have run a foul of some CLS issues and was hoping that someone could provide some insight.
I have an enumeration as such:
<Flags()> _
Public Enum FormState
Read = 1
Edit = 2
Insert = 4
End Enum
And a class as such:
Public MustInherit Class Fields
Inherits System.Web.UI.UserControl
Public Property State() As Enumerators.FormState
Get
Return _State
End Get
Set(ByVal value As Enumerators.FormState)
_State = value
ToggleState(value)
End Set
End Property
Protected MustOverride Sub ToggleState(ByVal state As FormState)
End Class
When I attempt to compile this code I am left with a warning that the State property is not CLS compliant and neither is the state argument. How come? And how can I correct this problem to remove the warnings?
I've attempted to add the <CLSCompliant(True)> attribute to both items with no luck
I tried to disseminate the MSDN article Non-CLS-compliant 'MustOverride' member is not allowed in a CLS-compliant into the code with no results
I've tried changing the accessors to Friend instead of Public
I've tried specifying a type for the Enum (Integer and UInteger)
Looking at your code, the enum seems to be part of a class called enumerators. The class is not listed in your code, but I'm assuming that you have full control over it.
The class needs to be tagged with the CLS compliant attribute as well.
To remove the warnings add the following attributes so that the class, method and property look like this:
<CLSCompliant(False)> _
Public MustInherit Class Fields
Inherits System.Web.UI.UserControl
<CLSCompliant(False)> _
Public Property State() As Enumerators.FormState
Get
Return _State
End Get
Set(ByVal value As Enumerators.FormState)
_State = value
ToggleState(value)
End Set
End Property
<CLSCompliant(False)> _
Protected MustOverride Sub ToggleState(ByVal state As FormState)
End Class
This signifies to the compiler that you want the warnings removed and that you're aware your code is not CLSCompliant.
It could be that you do not have an item with value 0.