[Assembly].LoadFrom()

  • Thread starter Thread starter Rui Dias
  • Start date Start date
R

Rui Dias

Hi there!
I've searched a lot and haven't found any clue to solve my problem.
I'm programming in VB.NET several DLL's wich are to be called by a single EXE. How does it know how to call them? It goes to a DB and gets DLL's name and corresponding Form name.
Example: "./Documental.dll" and "Documental.frmDocument"

Off course Documental DLL and the main EXE are in the same directory. However it works only, I say, 60% of the times. Other times it gives an error looked like this:

System.IO.FileNotFoundException
File or assembly name Documental.dll, or one of its dependencies, was not found.
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Boolean isStringized, Evidence assemblySecurity, Boolean throwOnFileNotFound, Assembly locationHint, StackCrawlMark& stackMark)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Boolean stringized, Evidence assemblySecurity, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence securityEvidence)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)

Could any one help me with this? I'm getting bold just thinking of this.

Thank you in advance!
Rui Dias
 
I'm doing something very similar. In my case, I have a Service application
that hits the database to get a list of DLL's / Classes to load. You will
need to store in your database, the fully qualified path to the file, and
the fully qualified namespace of the items you are trying to load. Below,
the OnStart sub is the entry point of my service where it gets a DataTable
of "reflective" information, and then passes each DataRow to CreateWatcher()
to return the reflection-created object into a collection: (watch out for
line wrapping)


Protected Overrides Sub OnStart(ByVal args() As String)

Dim cnstr As String
Dim da As SqlDataAdapter
Dim dt As New DataTable("FileListener")
Dim dr As DataRow
Dim fw As FileWatcher

'=======================================================================
' Immediately sleep for 10 seconds. This only affects the amount of
' time it takes for the service to launch. The reason for this is
that
' you cannot launch a Windows Service in the debugger. You have to
' start it in the Service Control Manager and then use Debug ->
' Processes -> Attach to hook the debugger into it. By the time a
human
' gets the debugger going, the startup code is already done. So if
you
' want to debug the startup code, this gives you 10 seconds of time
to
' hook the debugger into the launching (sleeping) service and set a
' breakpoint before its thread wakes back up. Cool, huh?
Threading.Thread.Sleep(10000)

Try

'===================================================================
' The FileWatcher table in the database contains information on
how
' to configure the various FileWatcher subclasses. We will use
the
' CreateWatcher() method to return a fully configured watcher
from
' a DataRow.
cnstr = ConfigurationSettings.AppSettings("connectionString")

If cnstr = "" Then _
Throw New ArgumentNullException( _
"connectionString", "'connectionString' key " & _
"not found in .config file.")

da = New SqlDataAdapter("ActiveFileListenerSelect", cnstr)
da.SelectCommand.CommandType = CommandType.StoredProcedure

With da.SelectCommand.Parameters
.Add("@computerName", SqlDbType.NVarChar, 126)
.Item(0).Value =
Windows.Forms.SystemInformation.ComputerName
End With

da.Fill(dt)

'===================================================================
' Populate the FileWatchersCollection with FileWatcher instances
For Each dr In dt.Rows
_watchers.Add(CreateWatcher(dr))
Next

'===================================================================
' Finalize Initialization
log.WriteEntry("Startup complete.",
EventLogEntryType.Information)
_watchers.Enabled = True

Catch ex As Exception
log.WriteEntry("Startup failed: " & ex.ToString(),
EventLogEntryType.Error)
Throw ex

End Try

End Sub

Public Function CreateWatcher(ByVal dataRow As DataRow) As FileWatcher

'=======================================================================
' Here's the fun part. If we get the AssemblyName and ClassName for
a
' FileWatcher out of the database, we can use reflection to create
the
' runtime instances. This way, future new FileWatcher subclasses
can be
' written in their own assemblies and listed in the FileWatcher
table.
' Then, to make them active, all you have to do is to restart this
' service. No need to disturb the code.

Dim watchAssembly As [Assembly]
Dim watchInstance As FileWatcher

Try
' Assembly.LoadFrom("c:\thisdir\thisassembly.dll")
watchAssembly =
[Assembly].LoadFrom(dataRow("AssemblyName").ToString())

' Assembly.CreateInstance("ThisNamespace.ThisClass") then CType
it
watchInstance = CType( _
watchAssembly.CreateInstance(dataRow("ClassName").ToString())
_
, FileWatcher)

' Anything that inherits from FileWatcher has these properties
With watchInstance
.ArchiveAction = CType(dataRow("ArchiveAction"),
ArchiveActions)
.ArchivePath = dataRow("ArchivePath").ToString()
.BatchSize = CType(dataRow("BatchSize"), Integer)
.FilenameRegEx = dataRow("FilenameRegEx").ToString()
.Logger = log
.MonitorPath = dataRow("MonitorPath").ToString()
'.Enabled = False
End With

Return watchInstance

Catch exc As Exception
log.WriteEntry("Failed to create watcher using reflection: " &
exc.ToString(), EventLogEntryType.Error)
End Try

End Function

--
Peace & happy computing,

Mike Labosh, MCSD
"I have no choice but to believe in free will."
Hi there!
I've searched a lot and haven't found any clue to solve my problem.
I'm programming in VB.NET several DLL's wich are to be called by a single
EXE. How does it know how to call them? It goes to a DB and gets DLL's name
and corresponding Form name.
Example: "./Documental.dll" and "Documental.frmDocument"

Off course Documental DLL and the main EXE are in the same directory.
However it works only, I say, 60% of the times. Other times it gives an
error looked like this:

System.IO.FileNotFoundException
File or assembly name Documental.dll, or one of its dependencies, was not
found.
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase,
Boolean isStringized, Evidence assemblySecurity, Boolean
throwOnFileNotFound, Assembly locationHint, StackCrawlMark& stackMark)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Boolean
stringized, Evidence assemblySecurity, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence
securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence
securityEvidence)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)

Could any one help me with this? I'm getting bold just thinking of this.

Thank you in advance!
Rui Dias
 
Thats exactly what I'm doing. However I have this challenge I'de like to
share with you.
I'm using this in development, with my team. Each one of us is compiling to
their computer and the DB is global.
Using Fully Qualified Names becames a problem. But you have a point, if I
use this in production.
........Thinking......
........ still thinking.....

Can't get a solution to this :(

Mike Labosh said:
I'm doing something very similar. In my case, I have a Service
application that hits the database to get a list of DLL's / Classes to
load. You will need to store in your database, the fully qualified path
to the file, and the fully qualified namespace of the items you are trying
to load. Below, the OnStart sub is the entry point of my service where it
gets a DataTable of "reflective" information, and then passes each DataRow
to CreateWatcher() to return the reflection-created object into a
collection: (watch out for line wrapping)


Protected Overrides Sub OnStart(ByVal args() As String)

Dim cnstr As String
Dim da As SqlDataAdapter
Dim dt As New DataTable("FileListener")
Dim dr As DataRow
Dim fw As FileWatcher


'=======================================================================
' Immediately sleep for 10 seconds. This only affects the amount
of
' time it takes for the service to launch. The reason for this is
that
' you cannot launch a Windows Service in the debugger. You have to
' start it in the Service Control Manager and then use Debug ->
' Processes -> Attach to hook the debugger into it. By the time a
human
' gets the debugger going, the startup code is already done. So if
you
' want to debug the startup code, this gives you 10 seconds of time
to
' hook the debugger into the launching (sleeping) service and set a
' breakpoint before its thread wakes back up. Cool, huh?
Threading.Thread.Sleep(10000)

Try


'===================================================================
' The FileWatcher table in the database contains information on
how
' to configure the various FileWatcher subclasses. We will use
the
' CreateWatcher() method to return a fully configured watcher
from
' a DataRow.
cnstr = ConfigurationSettings.AppSettings("connectionString")

If cnstr = "" Then _
Throw New ArgumentNullException( _
"connectionString", "'connectionString' key " & _
"not found in .config file.")

da = New SqlDataAdapter("ActiveFileListenerSelect", cnstr)
da.SelectCommand.CommandType = CommandType.StoredProcedure

With da.SelectCommand.Parameters
.Add("@computerName", SqlDbType.NVarChar, 126)
.Item(0).Value =
Windows.Forms.SystemInformation.ComputerName
End With

da.Fill(dt)


'===================================================================
' Populate the FileWatchersCollection with FileWatcher
instances
For Each dr In dt.Rows
_watchers.Add(CreateWatcher(dr))
Next


'===================================================================
' Finalize Initialization
log.WriteEntry("Startup complete.",
EventLogEntryType.Information)
_watchers.Enabled = True

Catch ex As Exception
log.WriteEntry("Startup failed: " & ex.ToString(),
EventLogEntryType.Error)
Throw ex

End Try

End Sub

Public Function CreateWatcher(ByVal dataRow As DataRow) As FileWatcher


'=======================================================================
' Here's the fun part. If we get the AssemblyName and ClassName
for a
' FileWatcher out of the database, we can use reflection to create
the
' runtime instances. This way, future new FileWatcher subclasses
can be
' written in their own assemblies and listed in the FileWatcher
table.
' Then, to make them active, all you have to do is to restart this
' service. No need to disturb the code.

Dim watchAssembly As [Assembly]
Dim watchInstance As FileWatcher

Try
' Assembly.LoadFrom("c:\thisdir\thisassembly.dll")
watchAssembly =
[Assembly].LoadFrom(dataRow("AssemblyName").ToString())

' Assembly.CreateInstance("ThisNamespace.ThisClass") then CType
it
watchInstance = CType( _

watchAssembly.CreateInstance(dataRow("ClassName").ToString()) _
, FileWatcher)

' Anything that inherits from FileWatcher has these properties
With watchInstance
.ArchiveAction = CType(dataRow("ArchiveAction"),
ArchiveActions)
.ArchivePath = dataRow("ArchivePath").ToString()
.BatchSize = CType(dataRow("BatchSize"), Integer)
.FilenameRegEx = dataRow("FilenameRegEx").ToString()
.Logger = log
.MonitorPath = dataRow("MonitorPath").ToString()
'.Enabled = False
End With

Return watchInstance

Catch exc As Exception
log.WriteEntry("Failed to create watcher using reflection: " &
exc.ToString(), EventLogEntryType.Error)
End Try

End Function

--
Peace & happy computing,

Mike Labosh, MCSD
"I have no choice but to believe in free will."
Hi there!
I've searched a lot and haven't found any clue to solve my problem.
I'm programming in VB.NET several DLL's wich are to be called by a single
EXE. How does it know how to call them? It goes to a DB and gets DLL's
name and corresponding Form name.
Example: "./Documental.dll" and "Documental.frmDocument"

Off course Documental DLL and the main EXE are in the same directory.
However it works only, I say, 60% of the times. Other times it gives an
error looked like this:

System.IO.FileNotFoundException
File or assembly name Documental.dll, or one of its dependencies, was not
found.
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String
codeBase, Boolean isStringized, Evidence assemblySecurity, Boolean
throwOnFileNotFound, Assembly locationHint, StackCrawlMark& stackMark)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef,
Boolean stringized, Evidence assemblySecurity, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence
securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence
securityEvidence)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)

Could any one help me with this? I'm getting bold just thinking of this.

Thank you in advance!
Rui Dias
 
Hi,

What about specifying assembly binding and private paths in the EXE's ..config file?

--
Sincerely,
Dmitriy Lapshin [C# / .NET MVP]
Bring the power of unit testing to the VS .NET IDE today!
http://www.x-unity.net/teststudio.aspx
Hi there!
I've searched a lot and haven't found any clue to solve my problem.
I'm programming in VB.NET several DLL's wich are to be called by a single EXE. How does it know how to call them? It goes to a DB and gets DLL's name and corresponding Form name.
Example: "./Documental.dll" and "Documental.frmDocument"

Off course Documental DLL and the main EXE are in the same directory. However it works only, I say, 60% of the times. Other times it gives an error looked like this:

System.IO.FileNotFoundException
File or assembly name Documental.dll, or one of its dependencies, was not found.
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Boolean isStringized, Evidence assemblySecurity, Boolean throwOnFileNotFound, Assembly locationHint, StackCrawlMark& stackMark)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Boolean stringized, Evidence assemblySecurity, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence securityEvidence)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)

Could any one help me with this? I'm getting bold just thinking of this.

Thank you in advance!
Rui Dias
 
Correct me if I'm wrong...

But I think my problem would stay the same. I would have to have one file per developer/user.

However from my last post I made a little change to my code.



[Assembly].LoadFrom(Application.StartupPath & "\myAssembly.dll")



So far it seems to be working. I've got some hope that I'll raise my "60% of the times" to some value more pleasant :)



PS: Yes, I Know the example FormsOnTheFly where one use an XML file named <samenamefromexe>.config



Thank you very much for your help.

Hi,

What about specifying assembly binding and private paths in the EXE's ..config file?

--
Sincerely,
Dmitriy Lapshin [C# / .NET MVP]
Bring the power of unit testing to the VS .NET IDE today!
http://www.x-unity.net/teststudio.aspx
Hi there!
I've searched a lot and haven't found any clue to solve my problem.
I'm programming in VB.NET several DLL's wich are to be called by a single EXE. How does it know how to call them? It goes to a DB and gets DLL's name and corresponding Form name.
Example: "./Documental.dll" and "Documental.frmDocument"

Off course Documental DLL and the main EXE are in the same directory. However it works only, I say, 60% of the times. Other times it gives an error looked like this:

System.IO.FileNotFoundException
File or assembly name Documental.dll, or one of its dependencies, was not found.
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Boolean isStringized, Evidence assemblySecurity, Boolean throwOnFileNotFound, Assembly locationHint, StackCrawlMark& stackMark)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Boolean stringized, Evidence assemblySecurity, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence securityEvidence)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)

Could any one help me with this? I'm getting bold just thinking of this.

Thank you in advance!
Rui Dias
 
Thats exactly what I'm doing. However I have this challenge I'de like to
share with you.
I'm using this in development, with my team. Each one of us is compiling
to their computer and the DB is global.
Using Fully Qualified Names becames a problem. But you have a point, if I
use this in production.

Ah, I think I know what's happening... Here, when we implemented this
FileListener thing, running it on more than one computer did goofy things
because not all computers needed to have all the dll's and fully qualified
paths, because they were loading different assemblies, so we did this in the
database:

This table stores info that's global all instances of FileListener running
anywhere on the network:

CREATE TABLE dbo.FileListener
(
FileListenerKey INT NOT NULL IDENTITY(1, 1),
ClassName NVARCHAR(200) NOT NULL,
FilenameRegEx NVARCHAR(200) NOT NULL,
BatchSize INT NOT NULL DEFAULT 0 CHECK (BatchSize >= 0),
)
GO

This table stores info for FileListener running on specific computers. The
application uses the local computer name in the where clause when it gets
this info. That way, it only loads the assemblies it's supposed to:

CREATE TABLE dbo.FileListenerInstance
(
FileListenerInstanceKey INT NOT NULL IDENTITY(1, 1),
FileListenerKey INT NOT NULL,
ComputerName NVARCHAR(63) NOT NULL,
AssemblyName NVARCHAR(255) NOT NULL,
MonitorPath NVARCHAR(255) NOT NULL,
ArchivePath NVARCHAR(255) NOT NULL,
ArchiveAction INT NOT NULL DEFAULT 0 CHECK (ArchiveAction IN (0, 1,
2)),
Active BIT NOT NULL DEFAULT 0
)
GO

This way, each instance of FileListener running on each machine can
successfully operate by loading assembly names and config info from this:

CREATE PROCEDURE dbo.ActiveFileListenerSelect
(
@computerName NVARCHAR(63)
)
AS
SELECT AssemblyName, ClassName, MonitorPath, ArchivePath,
FilenameRegex, BatchSize, ArchiveAction
FROM FileListener
INNER JOIN FileListenerInstance
ON FileListenerInstance.FileListenerKey = FileListener.FileListenerKey
WHERE Active = 1
AND ComputerName = @computerName
GO
 
Why don't all develpers agree to keep assemblies in the same path on their
local machines.
Say C:\Assemblies. Or better yet, why don't you add those assemblies to GAC.

Rui Dias said:
Thats exactly what I'm doing. However I have this challenge I'de like to
share with you.
I'm using this in development, with my team. Each one of us is compiling to
their computer and the DB is global.
Using Fully Qualified Names becames a problem. But you have a point, if I
use this in production.
........Thinking......
........ still thinking.....

Can't get a solution to this :(

Mike Labosh said:
I'm doing something very similar. In my case, I have a Service
application that hits the database to get a list of DLL's / Classes to
load. You will need to store in your database, the fully qualified path
to the file, and the fully qualified namespace of the items you are trying
to load. Below, the OnStart sub is the entry point of my service where it
gets a DataTable of "reflective" information, and then passes each DataRow
to CreateWatcher() to return the reflection-created object into a
collection: (watch out for line wrapping)


Protected Overrides Sub OnStart(ByVal args() As String)

Dim cnstr As String
Dim da As SqlDataAdapter
Dim dt As New DataTable("FileListener")
Dim dr As DataRow
Dim fw As FileWatcher


'=======================================================================
' Immediately sleep for 10 seconds. This only affects the amount
of
' time it takes for the service to launch. The reason for this is
that
' you cannot launch a Windows Service in the debugger. You have to
' start it in the Service Control Manager and then use Debug ->
' Processes -> Attach to hook the debugger into it. By the time a
human
' gets the debugger going, the startup code is already done. So if
you
' want to debug the startup code, this gives you 10 seconds of time
to
' hook the debugger into the launching (sleeping) service and set a
' breakpoint before its thread wakes back up. Cool, huh?
Threading.Thread.Sleep(10000)

Try


'===================================================================
' The FileWatcher table in the database contains information on
how
' to configure the various FileWatcher subclasses. We will use
the
' CreateWatcher() method to return a fully configured watcher
from
' a DataRow.
cnstr = ConfigurationSettings.AppSettings("connectionString")

If cnstr = "" Then _
Throw New ArgumentNullException( _
"connectionString", "'connectionString' key " & _
"not found in .config file.")

da = New SqlDataAdapter("ActiveFileListenerSelect", cnstr)
da.SelectCommand.CommandType = CommandType.StoredProcedure

With da.SelectCommand.Parameters
.Add("@computerName", SqlDbType.NVarChar, 126)
.Item(0).Value =
Windows.Forms.SystemInformation.ComputerName
End With

da.Fill(dt)


'===================================================================
' Populate the FileWatchersCollection with FileWatcher
instances
For Each dr In dt.Rows
_watchers.Add(CreateWatcher(dr))
Next


'===================================================================
' Finalize Initialization
log.WriteEntry("Startup complete.",
EventLogEntryType.Information)
_watchers.Enabled = True

Catch ex As Exception
log.WriteEntry("Startup failed: " & ex.ToString(),
EventLogEntryType.Error)
Throw ex

End Try

End Sub

Public Function CreateWatcher(ByVal dataRow As DataRow) As FileWatcher


'=======================================================================
' Here's the fun part. If we get the AssemblyName and ClassName
for a
' FileWatcher out of the database, we can use reflection to create
the
' runtime instances. This way, future new FileWatcher subclasses
can be
' written in their own assemblies and listed in the FileWatcher
table.
' Then, to make them active, all you have to do is to restart this
' service. No need to disturb the code.

Dim watchAssembly As [Assembly]
Dim watchInstance As FileWatcher

Try
' Assembly.LoadFrom("c:\thisdir\thisassembly.dll")
watchAssembly =
[Assembly].LoadFrom(dataRow("AssemblyName").ToString())

' Assembly.CreateInstance("ThisNamespace.ThisClass") then CType
it
watchInstance = CType( _

watchAssembly.CreateInstance(dataRow("ClassName").ToString()) _
, FileWatcher)

' Anything that inherits from FileWatcher has these properties
With watchInstance
.ArchiveAction = CType(dataRow("ArchiveAction"),
ArchiveActions)
.ArchivePath = dataRow("ArchivePath").ToString()
.BatchSize = CType(dataRow("BatchSize"), Integer)
.FilenameRegEx = dataRow("FilenameRegEx").ToString()
.Logger = log
.MonitorPath = dataRow("MonitorPath").ToString()
'.Enabled = False
End With

Return watchInstance

Catch exc As Exception
log.WriteEntry("Failed to create watcher using reflection: " &
exc.ToString(), EventLogEntryType.Error)
End Try

End Function

--
Peace & happy computing,

Mike Labosh, MCSD
"I have no choice but to believe in free will."
Hi there!
I've searched a lot and haven't found any clue to solve my problem.
I'm programming in VB.NET several DLL's wich are to be called by a single
EXE. How does it know how to call them? It goes to a DB and gets DLL's
name and corresponding Form name.
Example: "./Documental.dll" and "Documental.frmDocument"

Off course Documental DLL and the main EXE are in the same directory.
However it works only, I say, 60% of the times. Other times it gives an
error looked like this:

System.IO.FileNotFoundException
File or assembly name Documental.dll, or one of its dependencies, was not
found.
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String
codeBase, Boolean isStringized, Evidence assemblySecurity, Boolean
throwOnFileNotFound, Assembly locationHint, StackCrawlMark& stackMark)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef,
Boolean stringized, Evidence assemblySecurity, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence
securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence
securityEvidence)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)

Could any one help me with this? I'm getting bold just thinking of this.

Thank you in advance!
Rui Dias
 
Back
Top