How can I make a "RequiredIf" custom valid attribute in vb.net - vb.net

I am trying to create a customValidAttribute in VB.NET
Namespace EventRules
Public Class CustomRuleAttribute
Inherits ValidationAttribute
Protected Overrides Function IsValid(value As Object, validationContext as validationContext) As ValidationResult
If EventIsInOneWeek = True Then
'Property is required
End If
Return New ValidationResult(Me.FormatErrorMessage(validationContext.DisplayName))
End Function
And in my Interface
Imports System.ComponentModel.DataAnnotations
Imports EventRules
Namespace Contracts
Public Interface IEvent
Property EventIsInOneWeek As Boolean
<CustomRule()>
Property AdditionalProperty
So, the error I am getting is on EventIsInOneWeek and says "Reference to a non-shared member requires an object reference"
Edit: The object being passed in is a different property than 'EventIsInOneWeek', and I only want it to be required if EventIsInOneWeek is true.
Edit: Also updated the code more completely

As mentioned above -- the simple solution I was looking for was passing the entire business object in with validationContext. However, this exposes some security flaws in my system, so I created this work-around.
In my base business logic:
Public Overridable Function CheckRules() As Boolean
Me.Errors = New List(Of ValidationRules)()
Return Me.Validate(Me.Errors)
End Function
...
Public Overridable Function Validate(validationContext As ValidationContext) As IEnumerable(Of Validation Result) Implements IValidateObject.Validate
Return Nothing
End Function
And In my Business logic for the object itself
Protected Overrides Function Validate(validationContext As ValidationContext) As IEnumerable(Of Validation Result)
Dim results = New List(Of ValidationResult)()
'valiation conditionals here
Return results
End Function
I am passing my base logic into my Business Object, and it seems to be working well, unfortunately it does not auto generate front-end validation the way CustomValidationAttributes do.
This also allows me validationRules a little bit of re-usability that would not be afforded when passing a validationContext in.

Related

From A Method With In The Class Return An Instance Of The Class As An Interface Type That The Class Implements

what I'm trying to archive with the code below is to have the GetInstance generic function take in an interface type that SystemVars implements (say IAuthentication) then create an instance of SystemVars and return it as interface type T.
The problem I an having is that no matter what casting method I try I can't find a way to return the new instance of SystemVars as T. The line in the GetInstance method Return <CastingFunction>(New SystemVars,T) always fails to compile with the error message saying Value of type SystemVars cannot be converted to 'T'.
How do I return the instance of the class as the interface type that was passed into T?
Imports System.Drawing
Public Class SystemVars
Implements IAuthentication,
IAuthorization,
IApplicationStarting
Private Sub New()
End Sub
Public Shared Function GetInstance(Of T)() As T
Return DirectCast(New SystemVars, T)
End Function
Public ReadOnly Property Username As String _
Implements IAuthentication.Username,
IAuthorization.Username
Get
Return _userName
End Get
End Property
Public ReadOnly Property Rolls As List(Of String) _
Implements IAuthorization.Rolls
Get
Return _rolls
End Get
End Property
Public ReadOnly Property InstallationId As Guid _
Implements IAuthentication.InstallationId,
IApplicationStarting.InstallationId
Get
Return _installationId
End Get
End Property
Public ReadOnly Property MainWindowStartUpPlacement As Rectangle _
Implements IApplicationStarting.MainWindowStartUpPlacement
Get
Return _mainWindowStartUpPlacement
End Get
End Property
'........
Private Shared _userName As String
Private Shared _rolls As List(Of String)
Private Shared _installationId As Guid
Private Shared _mainWindowStartUpPlacement As Rectangle
End Class
You can make an otherwise illegal cast work by passing through Object.
Public Shared Function GetInstance(Of T)() As T
Return DirectCast(CObj(New SystemVars), T)
End Function
You will get a runtime error if the cast isn't possible; as noted in the comments, this strategy is chucking type safety out the window and basically telling the compiler, "Don't bother me, I know what I'm doing." The runtime will throw an InvalidCastException on failure if you don't test and throw yourself. You can test using Type.IsAssignableFrom if you want to create a more developer-friendly error message; there isn't much context available in the debugger at the point of failure, though it may be pretty obvious if you look up the call stack.
For just three interfaces, it might be better to do three separate specific functions rather than a generic version, especially considering that the functions are necessarily Shared (and thus can't themselves be part of an interface).
You might also consider a design that includes a Dependency Injection container. In this kind of design, there would be a configuration step that would associate the interfaces with SystemVars as the implementation, then the client would ask the container for an instance of the interface and receive a SystemVars object.
The rough way that the three options (the third being to cast the SystemVars object to the requested interface) would look in code is:
'Casting a received object to a requested interface
Dim asInterface = DirectCast(SystemVars.GetInstance(), IAuthorization)
'Using a custom casting function on SystemVars
Dim asInterface = SystemVars.GetInstance(Of IAuthorization)
'Using a DI container
'Behavior if the interface isn't supported depends on the container
Dim asInterface = container.GetInstance(Of IAuthorization)
Note that TryCast could be used instead of DirectCast, in which case the result would be Nothing if the interface isn't supported.

Make static member persistent

I have one class with a private static (shared, since I'm in VB.BET) field and its associated public static property, since it stores one variable that should be the same to all the instances of this class.
My Class looks like this:
Public MustInherit Class NitrogenController
Private _active As Boolean
Private Shared _controlInterval As TimeSpan
Private _lastControlTime As Date
Public Property Active() As Boolean
Public Shared Property ControlInterval() As System.TimeSpan
'other properies that must be persisted
Public Function Control() As Boolean
If Not Now > _lastControlTime.Add(_controlInterval) Or Not _active Then
Return False
Else
DoControl()
_lastControlTime = Now
Return True
End If
End Function
End Class
The problem arrives when trying to binary serialize these kind of objects, since this shared field is nos being properly stored and returns to its default value when deserializing.
I suppose this is the expected behaviour, so my question is... how can I make a shared field persistent? I have read some comments to similar questions that say that this is a bad design, but it really makes sense (AFAIK) in my case, since this variable should be the same to all the object, but can be changed by the user and therefore should be stored.
Can you suggest another way of doing it?
Thanks!
What you have read, in my opinion, is correct. This is, likely, a bad design. However, if you must, there are two ways to do this with the XmlSerializer. The easy way would be to simply add a public instance (non-shared) property which has a getter and setter which simply wrap the shared property, for instance:
Public MustInherit Class NitrogenController
Public Shared Property ControlInterval As TimeSpan
Public Property CurrentControlInterval() As TimeSpan
Get
Return ControlInterval
End Get
Set(value As TimeSpan)
ControlInterval = value
End Set
End Property
End Class
If you aren't satisfied with that method, the second, more involved, option would be to override the default serialization logic by implementing the ISerializable interface.

Linqkit Generic Predicates with VB.NET

I recently came across the wonderful Linqkit library and I want to make use of Generic Predicates to create a function for mapping users to the data they have access too accross any table that contains our data mapping fields. (H1L1, H1L2, etc)
Based on the tutorial (C# only) I see that this is indeed possible but I'm stuck.
So far I've created an interface:
Public Interface IDataMap
ReadOnly Property H1L1() As String
ReadOnly Property H1L2() As String
ReadOnly Property H1L3() As String
ReadOnly Property H2L1() As String
ReadOnly Property H2L2() As String
ReadOnly Property H2L3() As String
ReadOnly Property H3L1() As String
ReadOnly Property H3L2() As String
ReadOnly Property H3L3() As String
End Interface
Adjusted the Linq class for a table I'd like to operate on by adding
Implements IDataMap
and mapped each of the respective classes properties to the interface. I probably should have extended the linq class but for now i've just hardcoded the changes into the class generated by VS.
<Global.System.Data.Linq.Mapping.ColumnAttribute(Storage:="_H1L1", DbType:="VarChar(30)")> _
Public ReadOnly Property H1L1() As String Implements IDataMap.H1L1
Get
Return Me._H1L1
End Get
End Property
But I'm not sure where to go from here... or where to put this function so it's accessible from anywhere in my project. My test function is basic:
Public Shared Function mapUserToData(Of TEntity As IDataMap)(H1L1 As String) As Expression(Of Func(Of TEntity, Boolean))
Return Function(x) (H1L1 = x.H1L1))
End Function
Evenually I want to be able to say something similar to this:
DB.someTables.Where(someTable.mapUserToData("345BDS"))
The only way intellisense allows me to see that "mapUserToData" is available is if I put the function inside of my Linq Class... but then it's not generic. If I put the function inline in my code behind intellisense doesn't see my "mapUserToData" function as a method on my table. Maybe this is because of language/namespace differences between C# and VB.NET?
I'm a newbie to both .Net and Linq so please forgive me in advance for that.
I can use the linqkit predicate function successfully on an adhoc basis using
Dim predicate = PredicateBuilder.False(Of someTable)()
predicate = predicate.Or(Function(p) p.H1L1 IsNot Nothing)
Dim PgmED = (From x In DB.someTables.Where(predicate) Select x).AsEnumerable()
But can't afford to replicate the data mapping logic each time I need it. If anyone knows how to help I will be forever in their debt!
Try putting the mapUserToData function in a module as an Extension Method. Make it an extension of the IDataMap Interface.
<Extension()> _
Public Function mapUserToData(Of TEntity As IDataMap)(ByVal objTarget As IDataMap, H1L1 As String) As Expression(Of Func(Of TEntity, Boolean))
Return Function(x) (H1L1 = x.H1L1)
End Function

Have implemented IEquatable correctly? Should I always override GetHashCode?

I saw the question posed here: Have I implemented Equals()/GetHashCode() correctly? but my c# is not as strong, and I am unfimiliar with IEquatable enough that I would like to see this in VB.NET if possible please.
My example code (The class will eventually use INotifyPropertyChanged when I get there):
Public Class Car
Implements ICloneable
Implements IEquatable(Of Car)
Public Property Make() As String
Get
Return m_Make
End Get
Set(ByVal value As String)
m_Make = value
End Set
End Property
Private m_Make As String
Public Property Model() As String
Get
Return m_Model
End Get
Set(ByVal value As String)
m_Model = value
End Set
End Property
Private m_Model As String
Public Function Clone() As Object Implements System.ICloneable.Clone
Return New Car() With { _
.Make = Me.Make, _
.Model = Me.Model _
}
End Function
Public Overloads Function Equals(ByVal other As Car) As Boolean Implements System.IEquatable(Of Car).Equals
Return other.Make = Me.Make AndAlso other.Model = Me.Model
End Function
End Class
Thanks,
You really do need to implement Overrides for the object.Equals and object.GetHashCode implementations.
Basically, implementing IEquatable(of T).Equals by itself will only work so long as the caller KNOWS to call IEquatable(of T).Equals instead of regular object.Equals.
Consider if you have an ArrayList of Cars and check if the list Contains(myCar), where myCar's Make and Model are the same as a car in the ArrayList...but the one in the ArrayList isn't actually the exact same instance. Contains would return false.
Worse yet, if you had a Hashtable or Dictionary, which uses GetHashCode to determine where to store entries, equality would never work because two cars with the same Make and Model would return different values for GetHashCode()
Basically, it comes down to you adding the following implementations to car:
Public Overrides Overloads Function Equals(obj As Object) As Boolean
Return TypeOf obj Is Car AndAlso Equals(DirectCast(obj, Car))
End Function
Public Overrides Function GetHashCode() As Int32
Dim hash As Int32 = 179 ' or something intelligent
hash = hash * 27 + Make.GetHashCode()
hash = hash * 27 + Model.GetHashCode()
Return hash
End Function
So the question I have is: why implement IEquatable at all? Why not just override Equals and GetHashCode?
Only implement IEquatable<T> for structs or sealed classes. Any legitimate implementation of IEquatable<T>.Equals(T) needs to have semantics compatible with the class's override of Object.GetHashCode(), which must in turn have semantics compatible with the class's override of Equals(Object). If a type is not sealed, the only way to ensure that derived types' implementation of IEquatable<T>.Equals(T) will be compatible with their override of Object.Equals(Object) will be to have the former method chain to the latter, effectively nullifying any advantage one might have obtained from implementing IEquatable<T> in the first place.
Implementing IEquatable<T> is often a big win for struct types (saves a boxing operation on every comparison), and a somewhat smaller win for other sealed types (saves a typecast on every comparison). Unless performance is critical, I'd probably skip it for most non-struct types, even if they're sealed.

After restricting Setter scope and then applying an interface, scope is disregarded!

If I set a Friend-level scope on a setter, like this...
Public Class MyClass
Public Property IsDirty() As Boolean
Get
Return _isDirty
End Get
Friend Set(ByVal trueFalse As Boolean)
_isDirty = trueFalse
End Set
End Property
End Class
...And then call it from another project, it works correctly. I can't do something like MyClass.IsDirty = True.
Great! That's exactly what I want.
But now if I define an interface, and I will indeed have to do that:
Public Interface IMyClass
Property IsDirty() As Boolean
End Interface
I can do something like:
Dim MyInstance as IMyClass= GetSomeInstanceOfMyClass()
MyInstance.IsDirty=True
...And, bizarrely, it runs! No exceptions are thrown, and the inner variable is set to True. It ignores the Friend scope completely!
That's hideous. What am I missing??
Note: I need this because I'm designing an API, and I want the inner API to be able to set IsDirty, but end-developers shouldn't be able to get into that. Currently I am wrapping the whole class in a facade to get this functionality, but the facade should be unecessary.
Interface methods always have public accessibility. You can't fix that by explicit interface implementation, that will only hide the class method. Simply casting the object to the interface type gives unfettered access again.
EDIT: actually, the problem is easy to solve. Just declare the property ReadOnly in the interface declaration :)
For example:
Public Interface IMyClass
ReadOnly Property IsDirty() As Boolean
End Interface
Public Class Test
Implements IMyClass
Private mIsDirty As Boolean
Private ReadOnly Property IsDirtyImpl() As Boolean Implements IMyClass.IsDirty
Get
Return mIsDirty
End Get
End Property
Public Property IsDirty() As Boolean
Get
Return mIsDirty
End Get
Friend Set(ByVal value As Boolean)
mIsDirty = value
End Set
End Property
End Class
What you are missing is the concept of inplicit and explicit interface implementation. See the answer to this question for more details.
And if you think it's hideous with a Friend setter, try setting it to Private and watch it still be accessible via the interface!