Out of Stack Space Error when setting Custom Object Parameter - vba

I have a custom class module called Service with string parameters.
I instantiate the class by creating an object this_service like so:
Dim this_service As Service
Set this_service = New Service
Then I try to set a parameter to any string value like so:
this_service.Key = "HELLO"
When I run the macro I get the 28 Runtime Error, Out of Stack Space.
In my class module Service I have the following parameter definition and method calls:
Private pKey As String
Public Property Get Key() As String
Key = pKey
End Property
Public Property Let Key(Value As String)
Key = Value
End Property
I can't see any reason why I'd be getting this runtime error?

In Public Property Let it should be:
pKey = Value
Right now it calls the setter recursively (indefinitely).

Related

How to access properties of a class using Object type variable?

I have declared a "variable" of type OBJECT. I have also declared a class named TEST which has a property "name". My understanding is that in the statement variable = New test() the compiler is creating a new instance of the class TEST and storing the reference/memory address of that newly created instance in "variable". The idea is that an object type of variable should be able to store any type of data or its reference. By that logic using the member accessor operator I should be able to access the property "name" using "variable". But I am unable to. Can someone please explain why and how to access the property when the reference to the instance is being stored in an object type variable?
Module Program
Sub Main()
Dim variable As Object
variable = New test()
Console.WriteLine("Value: {0} Type: {1}", variable, variable.GetType())
'Output is Type: Object_Data_Type.test --> Works
'However we cannot access the property name of the class TEST through "varibale"
Console.ReadLine()
End Sub
End Module
Public Class test
Public Property name As String
End Class
Because an Object doesn't have a name property, and (on the outside) your variable looks like Object. If you want it to look like Test you'll have to cast it:
Console.WriteLine("Value: {0} Type: {1}", DirectCast(variable, Test).name, variable.GetType())

How can i assign a App Setting to Private Constant

I am storing some program values in my Web.config file and would like to use them in my Code.
When i try to set the value like this.
Private Const Security As String = ConfigurationManager.AppSettings("jwtKey")
i get the error Constant expression is required. Is there a way to make this work or do i have to assign the value to each function in my controller which needs access to this constant.
An option is to use the ReadOnly attribute:
Private ReadOnly Security As String = ConfigurationManager.AppSettings("jwtKey")
From the MSDN article:
Specifies that a variable or property can be read but not written.
Just what you are describing, assign a value to a variable but do not allow it to be changed.
This what a constructor is for
Class MyController
Private Const Security As String
Public Sub New
Security = ConfigurationManager.AppSettings("jwtKey")
End Sub
If you're using DI, you could pass all the relevant options in as a single object

Entity Framework errors while saving base class if there is any inheritance

I am using EF 6.1. I have a model "Request" built from the wizard directly from my database. In my context file (EMContext.vb) I have
Public Overridable Property Requests As DbSet(Of Request)
When I type in
Dim db As New EMContext
Dim req As New Request()
With req
.RequestedBy = "bar"
.EventName = "Goo"
.RequestedOn = Now
.RequestStatusID = 1
End With
db.Requests.Add(req)
db.SaveChanges()
everything works exactly as expected. No problems. It saves.
However, if I add a class (anywhere in the app)
Class foo
Inherits Request
Public Property s As String
End Class
and then run the exact same code I get
{"An error occurred while updating the entries. See the inner exception for details."}
Looking at the inner exception:
{"Invalid column name 's'.
Invalid column name 'Discriminator'."}
Why in the heck is it even looking at the inherited class properties?
BTW, if I remove all the properties from the inherited class, I still get the Invalid Column 'Discriminator' error.
Then create a custom class that the json parses to and then you can call the Entity and make it from this class.
<Serializable()>
Public Class jSonParsedObject
'properties that match the Entity object
'custom properties you need for other work
End Class
Usage:
Dim jsonObj As jSonParsedObject = SomeMethodThatParsesAndReturnsData()
Dim req As New Request()
With req
.RequestedBy = jsonObj.RequestedBy
.EventName = jsonObj.EventName
.RequestedOn = jsonObj.RequestedOn
.RequestStatusID = jsonObj.RequestStatusID
End With
...

Using VB.net Collection class via COM returns error: "Class doesn't support automation"

I have an existing VB.net class library which has a public property with a type of VB's Collection class. I'm exposing the class library as a COM-object to be able to use it in Progress.
When I access the Collection-property with an integer index (e.g. comObj.OutputCol.Item(1)) it works fine, but when I try to use the string indexer (e.g. comObj.OutputCol.Item("FirstCol")) I get the following error (from a VBScript I use for testing):
Error message: Class doesn't support automation
Error code: 800A01AE
Is it possible to use the string indexer in any way via COM?
Sample code, COM-object i VB.net:
<ComClass(TestClass.ClassId, TestClass.InterfaceId, TestClass.EventsId)>
Public Class TestClass
Public Const ClassId As String = "063CA388-9926-44EC-B3A6-856D5299C210"
Public Const InterfaceId As String = "094ECC57-4E84-423A-B20E-BD109AEDBC20"
Public Const EventsId As String = "038B18BD-54B4-42D3-B868-71F4C52345B0"
Private _sOutputCol As Collection = Nothing
Private Property sOutputCol() As Collection
Get
If _sOutputCol Is Nothing Then
_sOutputCol = New Collection()
End If
Return _sOutputCol
End Get
Set(ByVal Value As Collection)
_sOutputCol = Value
End Set
End Property
Public ReadOnly Property OutputCol() As Collection
Get
Return sOutputCol
End Get
End Property
Public Sub New()
sOutputCol.Add("First object", "FirstCol")
sOutputCol.Add(2, "SecondCol")
End Sub
End Class
Sample test-code in VBScript:
Set comObj = WScript.CreateObject("VbComTest.TestClass")
wscript.echo comObj.OutputCol.Item(1) ' Works
wscript.echo comObj.OutputCol.Item(CStr("FirstCol")) ' Gives the error
I have registred the dll with: >regasm "...path...\VbComTest.dll" /codebase
OK, the problem was that the indexer is overloaded and you shouldn't use that in COM-visible interfaces: https://msdn.microsoft.com/en-us/library/ms182197.aspx
Extract from the page about what happens to overloaded methods:
When overloaded methods are exposed to COM clients, only the first
method overload retains its name. Subsequent overloads are uniquely
renamed by appending to the name an underscore character '_' and an
integer that corresponds to the order of declaration of the overload.
For example, consider the following methods.
void SomeMethod(int valueOne); void SomeMethod(int valueOne, int
valueTwo, int valueThree); void SomeMethod(int valueOne, int
valueTwo);
These methods are exposed to COM clients as the following.
void SomeMethod(int valueOne); void SomeMethod_2(int valueOne,
int valueTwo, int valueThree); void SomeMethod_3(int valueOne, int
valueTwo);
Visual Basic 6 COM clients cannot implement interface methods by using
an underscore in the name.
So to use the string indexer I have to write:
wscript.echo comObj.OutputCol.Item_3("FirstCol")
(Item_2 takes an Object as parameter and will also work, if the documentation is correct).

Only first DataAnnotation validation being applied

I'm currently working on a Winforms application written in VB.NET and implementing the Entity Framework (4.4). I want to add validation attributes to my entities so that I can validate them on the UI - just as I do in MVC.
I have created my 'Buddy Class' which contains an IsValid method and points to a 'MetaData' class that contains the data annotations.
Imports System.ComponentModel.DataAnnotations
Imports System.Runtime.Serialization
Imports System.ComponentModel
<MetadataTypeAttribute(GetType(ProductMetadata))>
Public Class Product
Private _validationResults As New List(Of ValidationResult)
Public ReadOnly Property ValidationResults() As List(Of ValidationResult)
Get
Return _validationResults
End Get
End Property
Public Function IsValid() As Boolean
TypeDescriptor.AddProviderTransparent(New AssociatedMetadataTypeTypeDescriptionProvider(GetType(Product), GetType(ProductMetadata)), GetType(Product))
Dim result As Boolean = True
Dim context = New ValidationContext(Me, Nothing, Nothing)
Dim validation = Validator.TryValidateObject(Me, context, _validationResults)
If Not validation Then
result = False
End If
Return result
End Function
End Class
Friend NotInheritable Class ProductMetadata
<Required(ErrorMessage:="Product Name is Required", AllowEmptyStrings:=False)>
<MaxLength(50, ErrorMessage:="Too Long")>
Public Property ProductName() As Global.System.String
<Required(ErrorMessage:="Description is Required")>
<MinLength(20, ErrorMessage:="Description must be at least 20 characters")>
<MaxLength(60, ErrorMessage:="Description must not exceed 60 characters")>
Public Property ShortDescription As Global.System.String
<Required(ErrorMessage:="Notes are Required")>
<MinLength(20, ErrorMessage:="Notes must be at least 20 characters")>
<MaxLength(1000, ErrorMessage:="Notes must not exceed 1000 characters")>
Public Property Notes As Global.System.String
End Class
The first line in the IsValid method registers the MetaData class (only way I could find that actually worked - otherwise no annotations were honored!). I then use the System.ComponentModel.Validator.TryValidateObject method to perform the validation.
When I call the IsValid method on an instance with an empty (null/nothing) ProductName the validation fails and the ValidationResults collection is populated with the correct error message. So far so good.....
However, if I call IsValid on an instance with a ProductName which is longer than 50 characters the validation passes despite the MaxLength attribute!
Also, if I call IsValid on an instance with a valid ProductName (not empty and not more than 50 characters) but without a ShortDescription the validation passes even though there is a Required annotation on that property.
What am I doing wrong here?
Try the other method signature for TryValidateObject() and explicitly set validateAllProperties to true:
Dim validation = Validator.TryValidateObject(
Me, context, _validationResults, true)