Silverlight - Reflection - dynamic class - Inject code in the setter - vb.net

In Silverlight, I use a Dynamic class. I want to call boolean function before set property, for example :
Private _MyVar as Object
Public Property MyVar as Object
Get
return _MyVar
End Get
Set(value as Object)
If IsUpdateProp(value,"MyVar") Then _myVar = value
End Set
End Property
Private Function IsUpdateProp(value as Object, key as string) as Boolean
If value Is Nothing AndAlso GetValueProperty(key) Is Nothing
OrElse (value IsNot Nothing AndAlso
GetValueProperty(key) IsNot Nothing AndAlso
value.Equals(GetValueProperty(key))) Then
Return False
End If
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(key))
Return True`
End Function
I want to make this with reflection, my code :
Dim dp As DynamicProperty = properties(i)
Dim fb As FieldBuilder = tb.DefineField("_" & dp.Name, dp.Type,
FieldAttributes.Private)
Dim pb As PropertyBuilder = tb.DefineProperty(dp.Name,
PropertyAttributes.HasDefault, dp.Type, Nothing)
Dim isModify = GetType(Dynamic.DynamicClass).GetMethod("SetModifyField",
New Type() {GetType(Object), GetType(String)})
Dim mbSet As MethodBuilder = tb.DefineMethod("set_" & dp.Name,
MethodAttributes.Public Or
MethodAttributes.SpecialName Or
MethodAttributes.HideBySig,
Nothing, New Type() {dp.Type})
Dim genSet As ILGenerator = mbSet.GetILGenerator()
Dim mLabel = genSet.DefineLabel
genSet.Emit(OpCodes.Nop)
genSet.Emit(OpCodes.Ldarg_0)
genSet.Emit(OpCodes.Ldarg_1)
genSet.Emit(OpCodes.Box, dp.Type)
genSet.Emit(OpCodes.Ldstr, dp.Name)
genSet.Emit(OpCodes.Call, isModify)
genSet.Emit(OpCodes.Call, GetType(Convert).GetMethod("ToBoolean",
New Type() {GetType(Object)}))
genSet.Emit(OpCodes.Stloc_0)
genSet.Emit(OpCodes.Ldloc_0)
genSet.Emit(OpCodes.Brfalse_S, mLabel)
genSet.Emit(OpCodes.Ldarg_0)
genSet.Emit(OpCodes.Ldarg_1)
genSet.Emit(OpCodes.Stfld, fb)
genSet.MarkLabel(mLabel)
genSet.Emit(OpCodes.Nop)
genSet.Emit(OpCodes.Nop)
genSet.Emit(OpCodes.Ret)
At runtime, when I call setvalue on my property I get this error message:
System.Security.VerificationException: Cette opération pourrait déstabiliser le runtime." & vbCrLf & " à DynamicClass1.set_MyVar(Nullable`1 )
Thanks

Related

How build dynamic where clause with string argument

I try to buid a method to add a where clause to a Linq-to-SQL request (return an IQueryable). I try several methods but always use ToString, Indexof... but this result is a sql request take all element and the filter made in linq. I see request in SQL Server profiler.
I want a method to do it with result is a sql request with where include inside
I work in Visual Studio 2017 with SQL Server 2016. I code in vb.net
I see an interesting thing in linq dynamic library. But I can't to adapt to my situation
<Extension()> _
Public Function Where(ByVal source As IQueryable, ByVal predicate As String, ByVal ParamArray values() As Object) As IQueryable
If source Is Nothing Then Throw New ArgumentNullException("source")
If predicate Is Nothing Then Throw New ArgumentNullException("predicate")
Dim lambda As LambdaExpression = DynamicExpression.ParseLambda(source.ElementType, GetType(Boolean), predicate, values)
Return source.Provider.CreateQuery( _
Expression.Call( _
GetType(Queryable), "Where", _
New Type() {source.ElementType}, _
source.Expression, Expression.Quote(lambda)))
End Function
But I don't need all this complex strucutre. It's some years I buid my utilities. But Need to upgrade it. Here my code of my utilities
<Extension()>
Public Function Where(ByVal source As IQueryable, ByVal predicate As String) As IQueryable
Dim param = Expression.Parameter(GetType(String), "x")
Return source.Provider.CreateQuery(
Expression.Call(
GetType(Queryable), "Where",
New Type() {source.ElementType},
source.Expression, Expression.Quote(Expression.Lambda(Expression.Constant(predicate), param))))
End Function
Public Function TFOAppliqueFiltreTri(Of T, MaClassDatas As Class)(Origins As IQueryable(Of T), ByVal MesDonnees As TableFullOption.PagerTabEnCours(Of MaClassDatas)) As IQueryable(of T)
Dim retour As New TableFullOption.LstRetour
'Colonne de filtre
Dim strWh As String = ""
Dim Filtredrecords As IQueryable(Of T)
For Each Sort In MesDonnees.MesOptions
Dim colName = Sort.ColName
If strWh.Length > 0 Then strWh = strWh & " AND "
strWh = strWh & String.Format(colName & " like '%{0}%'", Sort.Search)
Next
If strWh.Length > 0 Then
Filtredrecords = Origins.Where(strWh) '<- Here call Where
Else
Filtredrecords = Origins
End If
Return Filtredrecords
End Function
I get this error:
Aucune méthode générique 'Where' sur le type 'System.Linq.Queryable' n'est compatible avec les arguments de type et les arguments fournis..
Then my problem is to write correctly lambda expression. My predicate argument is : Column1 like '%aaa%'. I want rewrite where method of dynamicLinq to accept string argument :Column1 like '%aaa%' directly
Thanks for your help
Finally after lot of reading in google and few feelings and certainly lot of chance.
Public Function Where(Of TEntity)(source As IQueryable(Of TEntity), searchColumn As List(Of String), searchValue As String) As IQueryable(Of TEntity)
Dim cond As Expression = Nothing
Dim ParamExpr = Expression.Parameter(GetType(TEntity), "x")
Dim conCat2 = GetType(String).GetMethod("Concat", New Type() {GetType(String), GetType(String)})
Dim conCat4 = GetType(String).GetMethod("Concat", New Type() {GetType(String), GetType(String), GetType(String), GetType(String)})
Dim Delim = Expression.Constant("/")
Dim DateName = GetType(SqlFunctions).GetMethod("DateName", New Type() {GetType(String), GetType(Nullable(Of DateTime))})
Dim DatePart = GetType(SqlFunctions).GetMethod("DatePart", New Type() {GetType(String), GetType(Nullable(Of DateTime))})
Dim DblToString = GetType(SqlFunctions).GetMethod("StringConvert", New Type() {GetType(Nullable(Of Double))})
For Each cn In searchColumn
For Each colName In cn.Split("|")
If Not colName.estVide Then
Dim body As Expression = ParamExpr
For Each member In colName.Split(".")
body = Expression.PropertyOrField(body, member)
Next
Dim Tostr As Expression
If body.Type.FullName.Contains("String") Then
Tostr = body
ElseIf body.Type.FullName.Contains("DateTime") Then
Dim day = Expression.Call(Expression.Call(conCat2, Expression.Constant("0"), Expression.Call(DateName, Expression.Constant("day"), body)), "Substring", Nothing, Expression.Constant(0), Expression.Constant(2))
Dim Month = Expression.Call(DatePart, Expression.Constant("MM"), body)
Dim toDouble = Expression.Convert(Month, GetType(Nullable(Of Double)))
Dim mois = Expression.Call(conCat2, Expression.Constant("0"), Expression.Call(Expression.Call(DblToString, toDouble), "Trim", Nothing))
Dim an = Expression.Call(DateName, Expression.Constant("year"), body)
Tostr = Expression.Call(conCat2, Expression.Call(conCat4, day, Delim, mois, Delim), an)
Else
Tostr = Expression.Call(body, "Convert.ToString", Nothing)
'Tostr = Expression.Convert(body, GetType(String))
End If
Dim condPart = Expression.Call(Expression.Call(Tostr, "ToLower", Nothing), "Contains", Nothing, Expression.Call(Expression.Constant(searchValue), "ToLower", Nothing))
If cond Is Nothing Then
cond = condPart
Else
cond = Expression.OrElse(cond, condPart)
End If
End If
Next
Next
Return source.Provider.CreateQuery(Of TEntity)(Expression.Call(GetType(Queryable), "Where", New Type() {GetType(TEntity)}, source.Expression, Expression.Lambda(cond, ParamExpr)))
End Function
Now I've dynamic filter which generated a SQL request with complete clause where

vb.net autocad get blockreference winform

i use vb.net To dev winform app. I can take blockreference, block name"Tab1". Now i want Get this block To edit block attribute, but i don't know how to do that,i search on gg but have no result.
Dim appProgID As String = "Autocad.Application"
Dim fname As String = "C:\Users\Kid\Downloads\IDEA FOR TOOL\TEST\TABLE ATTRIBUTE.dwg"
Dim AcadType As Type = Type.GetTypeFromProgID(appProgID)
Dim AcadApp As Object = Activator.CreateInstance(AcadType)
Dim visargs() As Object = New Object(0) {}
visargs(0) = False
AcadApp.GetType().InvokeMember("Visible", BindingFlags.SetProperty, Nothing, AcadApp, visargs, Nothing)
Dim AcadDocs As Object = AcadApp.GetType().InvokeMember(
"Documents", BindingFlags.GetProperty, Nothing, AcadApp, Nothing)
Dim args() As Object = New Object(1) {}
args(0) = fname
args(1) = False
Dim AcDoc As Object = AcadDocs.GetType.InvokeMember(
"Open", BindingFlags.InvokeMethod, Nothing, AcadDocs, args, Nothing)
AcadApp.GetType.InvokeMember(
"ActiveDocument", BindingFlags.GetProperty, Nothing, AcadApp, Nothing, Nothing)
AcDoc = AcadApp.GetType.InvokeMember(
"ActiveDocument", BindingFlags.GetProperty, Nothing, AcadApp, Nothing, Nothing)
Dim AcadModel As Object = AcDoc.GetType.InvokeMember("modelspace", BindingFlags.GetProperty, Nothing, AcDoc, Nothing)
Dim entity As Object
For Each entity In AcadModel
If TypeName(entity) = "IAcadBlockReference" Then
'here i want to take this block has name "tab1"
End If
Next
You don't need to use InvokeMember, VB.NET supports late binding.
Dim acadType As Type = Type.GetTypeFromProgID("AutoCAD.Application")
Dim acadApp = Activator.CreateInstance(acadType)
acadApp.Visible = true
Dim doc = acadApp.Documents.Open("C:\Users\Kid\Downloads\IDEA FOR TOOL\TEST\TABLE ATTRIBUTE.dwg")
Dim entity
For Each entity In doc.ModelSpace
If entity.ObjectName = "AcDbBlockReference" AndAlso _
String.Equals(entity.Name, "Tab1", StringComparison.OrdinalIgnoreCase) Then
Dim att
For Each att In entity.GetAttributes()
If att.TagString = "A" Then
att.TextString = "Your value"
End If
Next
End If
Next
If you want to have autocompletion, you need to download the ObjectARX SDK and add the following COM references to your VS project:
C:\ObjectARX 20..\inc-x64\Autodesk.AutoCAD.Interop.dll
C:\ObjectARX 20..\inc-x64\Autodesk.AutoCAD.Interop.Common.dll
Then you will be able to use typed variables like this:
Dim acadApp As AcadApplication = Activator.CreateInstance(acadType)

Office Add In Memory Limit

I am developing a set of Office add ins that reads and writes templates and other files from a locally stored serialized object. Until now it has been going well, however, since I have been stress testing it by writing big amounts of data to this local object, and loading it into memory when reading from it, I have been getting SystemOutOfMemory exceptions. I do clean memory out each time I am done with this object, but simply loading it into memory can cause the exception be thrown.
The object is at most 100mb in size at any given time, so there is no way that it is using all the desktop resources to load this object into memory, so I have been wondering whether it may be that Microsoft limits the amount of memory that an add in may use.
What I would like to know is of anyone knows if there is a size limit and what it may be, as well as how to increase it if there is a limit present?
Thank you in advance for any advice given.
UPDATE:
Here is the code of the class that I am serializing:
Imports System.Environment
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices
<Serializable()> _
Public Class LocalDBObject
Private aOfficesDS As DataSet = New DataSet()
Private aFieldDS As DataSet = New DataSet()
Private aSectorsDS As DataSet = New DataSet()
Private aDocumentsDS As DataSet = New DataSet()
Private aLibraryDS As DataSet = New DataSet()
Private aRolesDS As DataSet = New DataSet()
Private aSettings As mySettings = New mySettings()
Private aUpdateDate As DateTime = DateTime.Now
Private aUser As UserInfo = New UserInfo()
Private aDistributionFilesDS As DataSet = New DataSet()
Public Property UpdateDate() As DateTime
Get
UpdateDate = aUpdateDate
End Get
Set(ByVal Value As DateTime)
aUpdateDate = Value
End Set
End Property
Public Property Settings() As mySettings
Get
Settings = aSettings
End Get
Set(ByVal Value As mySettings)
aSettings = Value
End Set
End Property
Public Property RolesDS() As DataSet
Get
RolesDS = aRolesDS
End Get
Set(ByVal Value As DataSet)
aRolesDS = Value
End Set
End Property
Public Property UserInfo() As UserInfo
Get
UserInfo = aUser
End Get
Set(ByVal Value As UserInfo)
aUser = Value
End Set
End Property
Public Shared Userfolder As String = GetFolderPath(SpecialFolder.ApplicationData) + "\CIM\" + Environment.UserName
Public Shared UserDistributionfolder As String = GetFolderPath(SpecialFolder.ApplicationData) + "\CIM\CIM Distribution Files"
Public Shared Function CheckFile() As Boolean
Return System.IO.File.Exists(Userfolder + "\LocalDB.dat")
End Function
Public Shared Sub Write(ByVal obj As LocalDBObject)
Serializer.Serialize2(obj, Userfolder + "\LocalDB.dat")
End Sub
Public Shared Function Read() As LocalDBObject
If Not System.IO.Directory.Exists(Userfolder) Then
System.IO.Directory.CreateDirectory(Userfolder)
End If
Dim obj As LocalDBObject = Serializer.deSerialize2(Userfolder + "\LocalDB.dat")
Return obj
End Function
Public Property DocumentsDS() As DataSet
Get
DocumentsDS = aDocumentsDS
End Get
Set(ByVal Value As DataSet)
aDocumentsDS = Value
End Set
End Property
Public Property LibraryDS() As DataSet
Get
LibraryDS = aLibraryDS
End Get
Set(ByVal Value As DataSet)
aLibraryDS = Value
End Set
End Property
Public Property OfficesDS() As DataSet
Get
OfficesDS = aOfficesDS
End Get
Set(ByVal Value As DataSet)
aOfficesDS = Value
End Set
End Property
Public Property FieldDS() As DataSet
Get
FieldDS = aFieldDS
End Get
Set(ByVal Value As DataSet)
aFieldDS = Value
End Set
End Property
Public Property SectorsDS() As DataSet
Get
SectorsDS = aSectorsDS
End Get
Set(ByVal Value As DataSet)
aSectorsDS = Value
End Set
End Property
Public Property DistributionDS() As DataSet
Get
DistributionDS = aDistributionFilesDS
End Get
Set(ByVal Value As DataSet)
aDistributionFilesDS = Value
End Set
End Property
Public Shared Function GetNameForLibaryGroup(ByVal FieldID As Integer, ByVal obj As LocalDBObject) As String
For Each dr As DataRow In obj.aFieldDS.Tables(0).Rows
If dr("FieldID") = FieldID Then
Return dr("FieldName")
End If
Next
Return ""
End Function
Public Shared Function GetFileForTemplate(ByVal DocID As Integer) As Byte()
Dim obj As CIMShared.LocalDBObject = CIMShared.LocalDBObject.Read()
For Each dr As DataRow In obj.DocumentsDS.Tables(0).Rows
If dr("docid") = DocID Then
Try
Dim data As Byte() = CType(dr("docdata"), Byte())
Return data
Catch ex As Exception
Return Nothing
End Try
End If
Next
Return Nothing
End Function
Public Shared Function GetFilenameForTemplate(ByVal DocID As Integer) As String
Dim obj As CIMShared.LocalDBObject = CIMShared.LocalDBObject.Read()
For Each dr As DataRow In obj.DocumentsDS.Tables(0).Rows()
If dr("docid") = DocID Then
Return Convert.ToString(LocalDBObject.Userfolder + "\" + dr("docName")) + "_" + Convert.ToString(dr("DocID")) + "." + Convert.ToString(dr("docext")).Substring(1)
End If
Next
Return Guid.NewGuid().ToString().Replace("-", "") + ".txt"
End Function
Public Shared Function GetFilenameOnlyForTemplate(ByVal DocID As Integer) As String
Dim obj As CIMShared.LocalDBObject = CIMShared.LocalDBObject.Read()
For Each dr As DataRow In obj.DocumentsDS.Tables(0).Rows()
If dr("docid") = DocID Then
Return Convert.ToString(dr("docName")) + "." + Convert.ToString(dr("docext")).Substring(1)
End If
Next
Return Guid.NewGuid().ToString().Replace("-", "") + ".txt"
End Function
Public Shared Function GetFilenameForPicture(ByVal DocID As Integer) As String
Dim obj As CIMShared.LocalDBObject = CIMShared.LocalDBObject.Read()
For Each dr As DataRow In obj.DocumentsDS.Tables(0).Rows()
If dr("docid") = DocID Then
Return Convert.ToString(LocalDBObject.Userfolder + "\" + dr("docName")) + "." + Convert.ToString(dr("docext")).Substring(1)
End If
Next
Return Guid.NewGuid().ToString().Replace("-", "") + ".txt"
End Function
Public Shared Function GetFileForLibrary(ByVal DocID As Integer) As Byte()
Dim obj As CIMShared.LocalDBObject = CIMShared.LocalDBObject.Read()
For Each dr As DataRow In obj.LibraryDS.Tables(0).Rows
If dr("docid") = DocID Then
Try
Dim data As Byte() = CType(dr("docdata"), Byte())
Return data
Catch ex As Exception
Return Nothing
End Try
End If
Next
Return Nothing
End Function
Public Shared Function GetFileLibaryDate(ByVal DocID As Integer) As DateTime
Dim obj As CIMShared.LocalDBObject = CIMShared.LocalDBObject.Read()
For Each dr As DataRow In obj.LibraryDS.Tables(0).Rows
If dr("docid") = DocID Then
Try
Dim adate As DateTime = Convert.ToDateTime(dr("docdateupdated"))
Return adate
Catch ex As Exception
Return DateTime.Now.AddYears(-100)
End Try
End If
Next
Return DateTime.Now.AddYears(-100)
End Function
Public Shared Function GetFilenameForLibary(ByVal DocID As Integer) As String
Dim obj As CIMShared.LocalDBObject = CIMShared.LocalDBObject.Read()
For Each dr As DataRow In obj.LibraryDS.Tables(0).Rows
If dr("docid") = DocID Then
Return Convert.ToString(LocalDBObject.Userfolder + "\" + dr("docName")) + "_" + Convert.ToString(dr("DocID")) + "." + Convert.ToString(dr("docext")).Substring(1)
End If
Next
Return Guid.NewGuid().ToString().Replace("-", "") + ".txt"
End Function
'EUGENE: Added this to get the distribution folders.
Public Shared Function GetDistributionFileDS() As List(Of Integer)
Dim LocalDocIDList As New List(Of Integer)
Dim obj As CIMShared.LocalDBObject = CIMShared.LocalDBObject.Read()
If obj.aDistributionFilesDS.Tables.Count > 0 Then
For Each Row As DataRow In obj.aDistributionFilesDS.Tables(0).Rows
LocalDocIDList.Add(Row("docid"))
Next
End If
Return LocalDocIDList
End Function
Public Shared Function GetDistributionFilePath(DocumentID As Integer) As String
Dim LocalDocumentPath As String = ""
Dim obj As CIMShared.LocalDBObject = CIMShared.LocalDBObject.Read()
For Each Row As DataRow In obj.aDistributionFilesDS.Tables(0).Rows
If Row("docid") = DocumentID Then
LocalDocumentPath = LocalDBObject.UserDistributionfolder + "\" + CStr(Row("docid")) + "-" + CStr(Row("docName")) + CStr(Row("docext"))
End If
Next
Return LocalDocumentPath
End Function
Public Shared Function GetDistributionFileData(DocumentID As Integer) As Byte()
Dim LocalDocumentData As Byte() = Nothing
Dim obj As CIMShared.LocalDBObject = CIMShared.LocalDBObject.Read()
For Each Row As DataRow In obj.aDistributionFilesDS.Tables(0).Rows
If Row("docid") = DocumentID Then
LocalDocumentData = CType(Row("docdata"), Byte())
End If
Next
Return LocalDocumentData
End Function
End Class
Here are the serializer functions that serializes the class, and that deserilizes the class.
Public Shared Sub Serialize(ByVal obj As LocalDBObject, ByVal FileName As String)
Dim Stream As New FileStream(FileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite)
Dim objStreamWriter As New StreamWriter(Stream)
Dim x As New XmlSerializer(obj.GetType)
x.Serialize(objStreamWriter, obj)
objStreamWriter.Close()
End Sub
Public Shared Function deSerialize(ByVal FileName As String) As LocalDBObject
Dim obj As New LocalDBObject()
Dim Stream As FileStream
Dim objStreamReader As StreamReader
Try
Stream = New FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
objStreamReader = New StreamReader(Stream)
Dim x As New XmlSerializer(obj.GetType)
obj = x.Deserialize(objStreamReader)
objStreamReader.Close()
Catch ex As Exception
obj = New LocalDBObject()
Try
Stream.Close()
Catch
End Try
Try
objStreamReader.Close()
Catch
End Try
End Try
Return obj
End Function
NOTE: I realize this is not the cleanest or neatest code, this is a former colleagues code that I am using and trying to resolve bugs on.
What is currently happening is that every time I de-serialize the class, which is about 300MB in size, I get a Out Of Memory Exception. In no way is this using all the computer memory, hence why I would like to find out if there is a memory usage limit on Microsoft Office add-ins?
What object are you talking about? Could you be more specific?
Anyway, I always suggest releasing underlying COM objects insteatly. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Office object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. Read more about that in the Systematically Releasing Objects article.

Problem Understanding Access Modifiers in VB.Net with List( Of Object)

I've recently been updating a lot of my code to comply with proper n-tier architecture and OO programming, following examples from a book.
I'm starting to get problems now because I don't fully understand the access modifiers.
If I run the following code I get an error at the line
Dim clientFamilyDataAccessLayer As New ClientFamilyDAO
in the BLL at the point it creates an instance of the DAL. The full error message is: "The type initializer for 'ClientFamilyDAO' threw an exception. ---> System.NullReferenceException: Object reference not set to an instance of an object."
How do I use these function to create a list of ClientFamily objects that I can then work with?
On my UI layer I'm creating a list of objects; ClientFamilies
Dim listOfClientFamilies As List(Of ClientFamily) = ClientFamily.GetClientFamiliesByKRM(selectedEmployee.StaffNumber)
This is the function in the BLL
Public Shared Function GetClientFamiliesByKRM(ByVal krmStaffNumber As Integer) As List(Of ClientFamily)
Dim clientFamilyDataAccessLayer As New ClientFamilyDAO
Return clientFamilyDataAccessLayer.GetClientFamiliesByKRM(krmStaffNumber)
End Function
and this is function in the DAL
Public Function GetClientFamiliesByKRM(ByVal staffNumber As Integer) As List(Of ClientFamily)
Dim currentConnection As SqlConnection = New SqlConnection(_connectionString)
Dim currentCommand As New SqlCommand
currentCommand.CommandText = mainSelectStatement & " WHERE Key_Relationship_Manager = #StaffNumber ORDER BY Client_Family_Name"
currentCommand.Parameters.AddWithValue("#StaffNumber", staffNumber)
currentCommand.Connection = currentConnection
Dim listOfClientFamilies As New List(Of ClientFamily)
Using currentConnection
currentConnection.Open()
Dim currentDataReader As SqlDataReader = currentCommand.ExecuteReader()
Do While currentDataReader.Read
Dim newClientFamily As AECOM.ClientFamily = PopulateClientFamily(currentDataReader)
listOfClientFamilies.Add(newClientFamily)
Loop
End Using
Return listOfClientFamilies
End Function
Here's the full ClientFamilyDAO Class:
Public Class ClientFamilyDAO
Private Const mainSelectStatement As String = "SELECT Client_Family_ID, Client_Family_Name, Key_Relationship_Organisation, Key_Relationship_Manager, Obsolete, Market_Sector_ID FROM Client_Families"
Private Shared ReadOnly _connectionString As String = String.Empty
Shared Sub New()
_connectionString = WebConfigurationManager.ConnectionStrings("ClientFamilyManagementConnectionString").ConnectionString
End Sub
Public Function GetClientFamiliesByKRM(ByVal staffNumber As Integer) As List(Of ClientFamily)
Dim currentConnection As SqlConnection = New SqlConnection(_connectionString)
Dim currentCommand As New SqlCommand
currentCommand.CommandText = mainSelectStatement & " WHERE Key_Relationship_Manager = #StaffNumber ORDER BY Client_Family_Name"
currentCommand.Parameters.AddWithValue("#StaffNumber", staffNumber)
currentCommand.Connection = currentConnection
Dim listOfClientFamilies As New List(Of ClientFamily)
Using currentConnection
currentConnection.Open()
Dim currentDataReader As SqlDataReader = currentCommand.ExecuteReader()
Do While currentDataReader.Read
Dim newClientFamily As AECOM.ClientFamily = PopulateClientFamily(currentDataReader)
listOfClientFamilies.Add(newClientFamily)
Loop
End Using
Return listOfClientFamilies
End Function
Private Function PopulateClientFamily(ByVal currentDataReader As SqlDataReader) As AECOM.ClientFamily
Dim newClientFamily As New AECOM.ClientFamily
If Not (currentDataReader.IsDBNull(currentDataReader.GetOrdinal("Client_Family_ID"))) Then
newClientFamily.ClientFamilyID = currentDataReader("Client_Family_ID")
End If
If Not (currentDataReader.IsDBNull(currentDataReader.GetOrdinal("Client_Family_Name"))) Then
newClientFamily.ClientFamilyName = currentDataReader("Client_Family_Name")
End If
If Not (currentDataReader.IsDBNull(currentDataReader.GetOrdinal("Key_Relationship_Organisation"))) Then
Select Case currentDataReader("Key_Relationship_Organisation")
Case False
newClientFamily.IsKeyRelationshipOrganisation = False
Case True
newClientFamily.IsKeyRelationshipOrganisation = True
End Select
End If
If Not (currentDataReader.IsDBNull(currentDataReader.GetOrdinal("Key_Relationship_Manager"))) Then
newClientFamily.KeyRelationshipManagerStaffNumber = currentDataReader("Key_Relationship_Manager")
End If
If Not (currentDataReader.IsDBNull(currentDataReader.GetOrdinal("Obsolete"))) Then
Select Case currentDataReader("Obsolete")
Case False
newClientFamily.Obsolete = False
Case True
newClientFamily.Obsolete = True
End Select
End If
If Not (currentDataReader.IsDBNull(currentDataReader.GetOrdinal("Market_Sector_ID"))) Then
newClientFamily.MarketSectorID = currentDataReader("Market_Sector_ID")
End If
Return newClientFamily
End Function
End Class
The issue doesn't relate to access modifiers, rather it is more to do with the exception message you get. The following line within the constructor of ClientFamilyDAO would seem to be causing the issue:
_connectionString = WebConfigurationManager.ConnectionStrings("ClientFamilyManagementConnectionString").ConnectionString
Are you sure ClientFamilyManagementConnectionString exists in the configuration?

How do I invoke HasValue on a nullable property of an object via reflection?

This function loops all properties of an object to create the updatequery to save te object to the DB.
We had to make some changes to it because of the introduction of nullable properties.
If the property is nullable we would like to check the 'HasValue' property.
This does works when it has a value. When the property has no value we get an 'Non-static method requires a target'-error at the CBool-line
Any suggestions?
An other way to check the 'HasValue'-prop of a property using reflection?
Thanks.
Private Function GetUpdateQuery(ByVal obj As Object, ByRef params As List(Of SqlParameter), Optional ByVal excl As String() = Nothing) As String
Dim sql As String = String.Empty
Dim props As PropertyInfo() = obj.GetType().GetProperties
If excl Is Nothing Then
excl = New String() {}
End If
For Each prop As PropertyInfo In props
Try
If Not excl.Contains(prop.Name) And prop.CanWrite = True Then
sql &= String.Format("{0} = #{1},", prop.Name, prop.Name)
Dim param As SqlParameter
Dim value As Object
If prop.PropertyType.IsGenericType AndAlso prop.PropertyType.GetGenericTypeDefinition() = GetType(Nullable(Of )) Then
If CBool(prop.PropertyType.GetProperty("HasValue").GetValue(prop.GetValue(obj, Nothing), Nothing)) Then
value = prop.GetValue(obj, Nothing)
Else
value = DBNull.Value
End If
Else
If prop.GetValue(obj, Nothing) = Nothing Then
value = DBNull.Value
Else
value = prop.GetValue(obj, Nothing)
End If
End If
param = ConnSql.CreateParameter("#" & prop.Name, value)
params.Add(param)
End If
Catch ex As Exception
End Try
Next
sql = sql.Substring(0, sql.Length - 1)
Return sql
End Function
You do not need the following If. You can remove it.
If prop.PropertyType.IsGenericType AndAlso prop.PropertyType.GetGenericTypeDefinition() = GetType(Nullable(Of )) Then
BUT you do need to fix the following If:
If prop.GetValue(obj, Nothing) = Nothing Then
to
If prop.GetValue(obj, Nothing) IS Nothing Then
--
Complete code:
Private Function GetUpdateQuery(ByVal obj As Object, ByRef params As List(Of SqlParameter), Optional ByVal excl As String() = Nothing) As String
Dim sql As String = String.Empty
Dim props As PropertyInfo() = obj.GetType().GetProperties
If excl Is Nothing Then
excl = New String() {}
End If
For Each prop As PropertyInfo In props
If Not excl.Contains(prop.Name) And prop.CanWrite = True Then
sql &= String.Format("{0} = #{1},", prop.Name, prop.Name)
Dim param As SqlParameter
Dim value As Object
If prop.GetValue(obj, Nothing) Is Nothing Then
value = DBNull.Value
Else
value = prop.GetValue(obj, Nothing)
End If
param = ConnSql.CreateParameter("#" & prop.Name, value)
params.Add(param)
End If
Next
sql = sql.Substring(0, sql.Length - 1)
Return sql
End Function