Hello I'm getting this error, while trying to save serial number to XML File.
If the file doesn't exist, it saves the file fine, but if i change Registered tag to False in Xml file, and try again, it says "The Process Cannot acces the file ... because it is being used by another process".
In my main form i read the information from XML, and in my regform (which i open if registered tag in xml is false) i write to the file. is it because of that?! I don't think so.
Here is my Registration class:
Imports System.IO
Imports System.Xml
Public Class RegistrationClass
Public Property SerialNumber As String
Public Property Registered As Boolean = False
Public Sub Write_Reg(ByVal FileString As String, ByVal RegisterName As String, ByVal RegisterCompany As String, ByVal RegisterSerialNumber As String)
Dim Registered As Boolean = False
Dim Comment As String = "StroySoft 2012 Register Database"
Dim SerialNumber As String = "dev-xxx-123"
Dim ClientOS As String = Trim(My.Computer.Info.OSFullName)
If RegisterSerialNumber = SerialNumber Then
Dim settings As New XmlWriterSettings()
settings.Indent = True
' Initialize the XmlWriter.
Dim XmlWrt As XmlWriter = XmlWriter.Create(FileString, settings)
With XmlWrt
' Write the Xml declaration.
.WriteStartDocument()
' Write a comment.
.WriteComment(Comment)
' Write the root element.
.WriteStartElement("Data")
' Start our first person.
.WriteStartElement("Register")
' The person nodes.
.WriteStartElement("Name")
.WriteString(RegisterName.ToString())
.WriteEndElement()
.WriteStartElement("Company")
.WriteString(RegisterCompany.ToString())
.WriteEndElement()
.WriteStartElement("SerialNumber")
.WriteString(RegisterSerialNumber.ToString())
.WriteEndElement()
Registered = True
.WriteStartElement("Registered")
.WriteString(Registered)
.WriteEndElement()
.WriteStartElement("ClientOS")
.WriteString(ClientOS)
.WriteEndElement()
' The end of this person.
.WriteEndElement()
' Close the XmlTextWriter.
.WriteEndDocument()
.Close()
End With
MsgBox("Успешна регистрация! Благодарим Ви!")
MainForm.РегистрацияToolStripMenuItem.Visible = False
Else
MsgBox("Невалиден сериен номер!")
End If
End Sub
Public Sub Check_Reg(ByVal FileString As String)
If (System.IO.File.Exists(FileString)) Then
Dim document As XmlReader = New XmlTextReader(RegForm.RegFile)
While (document.Read())
Dim type = document.NodeType
If (type = XmlNodeType.Element) Then
If (document.Name = "Registered") Then
If document.ReadInnerXml.ToString() = "True" Then
Registered = True
Else
Registered = False
End If
End If
If (document.Name = "SerialNumber") Then
SerialNumber = document.ReadInnerXml.ToString()
End If
End If
End While
Else
MessageBox.Show("The filename you selected was not found.")
End If
End Sub
End Class
is it because of that?! I don't think so.
It's exactly because of that.
You should always make sure to properly dispose IDisposable resources such as Streams and Writers/Readers by wrapping them in a Using block. In your case I don't see you closing your reader. But if you wrap it in a Using block you shouldn't worry about it. Even if an exception is thrown the resource will be properly released.
Example:
Using XmlWrt As XmlWriter = XmlWriter.Create(FileString, settings)
...
End Using
You should do the same with your XmlReader:
Using document As XmlReader = XmlReader.Create(RegForm.RegFile)
...
End Using
Related
I'm trying to implement functionality to allow the user to select his favorite forms. Favorite forms are forms he/she needs quick access to. To avoid browsing for too long through the ToolStripMenu's.
I try to save a reference to a form in the application configuration. But I'm getting the error
Value of type 'System.Windows.Forms.Form' cannot be converted to
'String'.
Public Sub SetSetting(ByVal pstrKey As String, ByVal frmFavorite As Form)
Dim keyExists As Boolean = False
For Each strKey As String In configuration.AppSettings.Settings.AllKeys
If strKey.Equals(pstrKey) Then
configuration.AppSettings.Settings.Item(pstrKey).Value = frmFavorite
keyExists = True
End If
Next
If Not keyExists Then
configuration.AppSettings.Settings.Add(pstrKey, frmFavorite)
End If
configuration.Save(ConfigurationSaveMode.Modified)
ConfigurationManager.RefreshSection("appSettings")
End Sub
You can only store string values in the application config file, no objects.
But just store the name of the Form in the config file.
When starting your application create the form via reflection like shown in this Object Factory example.
Public Class ObjectFactory
Public Shared Function CreateAnObject(ByVal ObjectName As String) As Object
Dim Assem = [Assembly].GetExecutingAssembly()
Dim myType As Type = Assem.GetType(ObjectName.Trim)
Dim o As Object = Nothing
Try
o = Activator.CreateInstance(myType)
Catch oEx As TargetInvocationException
MessageBox.Show(oEx.ToString)
End Try
Return o
End Function
End Class
...
Dim formName as String = configuration.AppSettings.Settings.Item(<YourSettingKey>)
Dim oForm As Form = _
ObjectFactory.CreateAnObject(formName)
I have a program that allows users to setup a client/server to control/run commands from a remote location. Now i'm trying to implement server plugins, and I'm doing that by loading every .vb file in a folder contained inside the current running directory. Everything is great, and the code from the external files compiles just fine... Only problem is, Its returning nothing when I try to compile the script and use one of the methods inside it.
Here's some code for you to check out. My error is in the 2nd. Any idea on how to fix this?
The Interaction Interface:
Public Interface LinkingInterface
Property name As String
Property statetag As String
Sub selected(ByVal Sock As Integer)
Sub deselected(ByVal Sock As Integer)
Sub load()
Function generateOutput(ByVal input As String, ByVal Sock As Integer) As String
End Interface
Detection/Loading of the "Modes" (add-ins):
For Each file In My.Computer.FileSystem.GetFiles("modes\")
Dim thisMode As LinkingInterface = LoadMode(My.Computer.FileSystem.ReadAllText(file))
thisMode.load() '<---------------------------My error is here, saying its a null ref.
modes_InterfaceCollection.Add(thisMode) 'Public modes_InterfaceCollection As New Microsoft.VisualBasic.Collection()
modes_nameIndex.Add(thisMode.name) 'Public modes_nameIndex As New Specialized.StringCollection()
Next
'LoadMode' Function
Public Function LoadMode(ByVal code As String) As LinkingInterface
Using provider As New VBCodeProvider()
Dim parameters As New CompilerParameters()
parameters.GenerateInMemory = True
parameters.ReferencedAssemblies.Add(Reflection.Assembly.GetExecutingAssembly().Location)
parameters.MainClass = "Remote_Command_Line.MainModule"
Dim interfaceNamespace As String = GetType(LinkingInterface).Namespace
Dim codeBuilder As New Text.StringBuilder
Dim namespaces() As String = New String() {"Microsoft.VisualBasic", "System", "System.Console", "System.Collections", "System.Collections.Generic", _
"System.Data", "System.Diagnostics", "Remote_Command_Line.MainModule"}
Dim codeString As New StringBuilder
For Each namespacestring As String In namespaces
codeString.AppendLine("Imports " & namespacestring)
Next
codeString.AppendLine(code)
Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, codeString.ToString)
'I commented out this just for debugging purposes
'If results.Errors.HasErrors Then
'For Each scriptError As CompilerError In results.Errors
'WriteLine(scriptError.ToString)
'Next
'Else
Return CType(results.CompiledAssembly.CreateInstance(results.CompiledAssembly.GetType.Name), LinkingInterface)
'End If
End Using
End Function
The Testing file 'test.vb':
Public Class test_mode
'Designed for RCL mode 1.0b
'Matthew 2013
'used for managing the local filesystem.
'####################################
#Region "Properties"
'all of these properties listed are required --------------------
Implements LinkingInterface
Property name As String Implements LinkingInterface.name 'the name the client refers to you in the 'modeswitch' command
Property statetag As String Implements LinkingInterface.statetag 'short tag displayed on the client when active before the input signal '>'
'----------------------------------------------------------------
Public curDirDatabank As New Specialized.StringCollection()
#End Region
'####################################
'####################################
#Region "Subs"
'Its required to have, but not required to do anything. This load sub is here for any modes that may require an initialization
Private Sub load() Implements LinkingInterface.load 'REQUIRED
name = "file" : statetag = "file"
MsgBox("Testing: It's loaded")
End Sub
Private Sub selected(ByVal Sock As Integer) Implements LinkingInterface.selected
MsgBox("Testing: '" & Sock & "' selected the File mode")
End Sub
Private Sub deselected(ByVal Sock As Integer) Implements LinkingInterface.deselected
MsgBox("Testing: '" & Sock & "' deselected the File mode")
End Sub
Private Function generateOutput(ByVal input As String, ByVal Sock As Integer) As String Implements LinkingInterface.generateOutput 'REQUIRED
Return ("Testing: '" & Sock & "' said '" & input & "'")
End Function
#End Region
'####################################
End Class
the following line is wrong.
Return CType(results.CompiledAssembly.CreateInstance(results.CompiledAssembly.GetType.Name), LinkingInterface)
You need to search through the loaded classes for one implementing your interface (it being VB you automatically get classes generated for the My namespace objects such as My.Computer)
Try this instead
For Each t As Type In results.CompiledAssembly.GetTypes()
If t.GetInterface(GetType(LinkingInterface).Name) IsNot Nothing Then
Return CType(results.CompiledAssembly.CreateInstance(t.Name), LinkingInterface)
End If
Next
Return Nothing
I'm working up a system where I plan on using RealProxy objects to enable intercepting method calls against a set of objects, handling the call, and then returning appropriate results.
This works just find for simple return types like strings or ints, but I can't seem to return objects from the RealProxy.Invoke method.
Everything works. I get no errors, but the returned value is always NOTHING, instead of an object.
I've worked up the smallest sample code I could, and have included it below.
Essentially, just call RPtest and single step through.
The code creates a simple object, RPTestA, with a string field and an object valued field
It then retrieves the string
Dim x = c.Name
Which works fine
and then attempts to retrieve the object
Dim r = c.SubObj
Which always returns nothing.
However, in the FieldGetter routine, this code:
'---- the field is an OBJECT type field
Dim mc = New MethodCallMessageWrapper(Msg)
'---- create the object
Dim o = Activator.CreateInstance(t)
'---- and construct the return message with that object
Dim r = New ReturnMessage(o, mc.Args, mc.Args.Length, mc.LogicalCallContext, mc)
Return r
appears to work just fine, setting the ReturnValue field of the ReturnMessage to the object that was created by the Activator.CreateInstance(t) call just above.
I suspect it's a serialization thing of some sort, but I'm at a loss.
You should be able to run this code straight away, but just pasting it into a new VB.net project.
'----------------------------------------------------------------------------
Imports System.Security.Permissions
Imports System.Diagnostics
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Runtime.Serialization
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Activation
Imports System.Runtime.Remoting.Messaging
Imports System.Runtime.Remoting.Proxies
Public Module RPTest
Public Sub RPTest()
'---- create a new object that is automatically proxied
' See the RPProxyAttribute for details
Dim c = New RPTestA
Dim x = c.Name
'x is returned as a string value just fine
Dim r = c.SubObj
'********* PROBLEM IS HERE, r ends up nothing
End Sub
End Module
'ROOT test object
Public Class RPTestA
Inherits RPBase
Public Name As String = "Test Name"
Public SubObj As RPTestB
End Class
'SUB OBJECT which should be returned as a field value from the root object above
Public Class RPTestB
Inherits RPBase
Public SubProperty As String = "SubObj Test Property"
End Class
''' <summary>
''' Base proxyable object class
''' </summary>
''' <remarks></remarks>
<RPProxy()> _
Public MustInherit Class RPBase
Inherits ContextBoundObject
End Class
<PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
Public Class RPProxy
Inherits RealProxy
Private m_target As MarshalByRefObject
Public Sub New()
m_target = DirectCast(Activator.CreateInstance(GetType(ConfigRP)), MarshalByRefObject)
Dim myObjRef = RemotingServices.Marshal(m_target)
End Sub
Public Sub New(ByVal classToProxy As Type)
MyBase.New(classToProxy)
End Sub
Public Sub New(ByVal ClassToProxy As Type, ByVal targetObject As MarshalByRefObject)
m_target = targetObject
Dim myObjRef = RemotingServices.Marshal(m_target)
End Sub
Public Overrides Function Invoke(ByVal msg As IMessage) As IMessage
Dim returnMsg As IMethodReturnMessage = Nothing
If TypeOf msg Is IConstructionCallMessage Then
'---- handle constructor calls
Dim ConstructionCallMessage = DirectCast(msg, IConstructionCallMessage)
returnMsg = InitializeServerObject(ConstructionCallMessage)
Me.m_target = Me.GetUnwrappedServer()
SetStubData(Me, Me.m_target)
Return returnMsg
ElseIf TypeOf msg Is IMethodCallMessage Then
'---- handle all other method calls
Dim methodCallMessage = DirectCast(msg, IMethodCallMessage)
'---- before message processing
preprocess(methodCallMessage)
'---- execute the method call
Dim rawReturnMessage = RemotingServices.ExecuteMessage(Me.m_target, methodCallMessage)
'---- and postprocess
returnMsg = postprocess(methodCallMessage, rawReturnMessage)
Else
Throw New NotSupportedException()
End If
Return returnMsg
End Function
'Called BEFORE the actual method is invoked
Private Sub PreProcess(ByVal msg As IMessage)
Console.WriteLine("before method call...")
End Sub
'Called AFTER the actual method is invoked
Private Function PostProcess(ByVal Msg As IMethodCallMessage, ByVal msgReturn As ReturnMessage) As ReturnMessage
Dim r As ReturnMessage
If Msg.MethodName = "FieldGetter" Then
r = FieldGetter(Msg, msgReturn)
ElseIf Msg.MethodName = "FieldSetter" Then
'na
r = msgReturn
ElseIf Msg.MethodName.StartsWith("get_") Then
'na
r = msgReturn
ElseIf Msg.MethodName.StartsWith("set_") Then
'na
r = msgReturn
Else
r = msgReturn
End If
Return r
End Function
Private Function FieldGetter(ByVal Msg As IMethodCallMessage, ByVal msgReturn As IMethodReturnMessage) As IMethodReturnMessage
Dim t = Me.Target.GetType
'---- This retrieves the type of the field that the getter should retrieve
t = t.GetField(Msg.InArgs(1), BindingFlags.Instance Or BindingFlags.Public).FieldType
If t.Name = "String" Then
'---- just return what the object returned as a result of ExecuteMessage
Return msgReturn
ElseIf t.BaseType.Equals(GetType(RPBase)) Then
'---- the field is an OBJECT type field
Dim mc = New MethodCallMessageWrapper(Msg)
'---- create the object
Dim o = Activator.CreateInstance(t)
'---- and construct the return message with that object
Dim r = New ReturnMessage(o, mc.Args, mc.Args.Length, mc.LogicalCallContext, mc)
Return r
Else
Return msgReturn
End If
End Function
Public Property Target() As Object
Get
Return Me.m_target
End Get
Set(ByVal value As Object)
Me.m_target = value
End Set
End Property
End Class
<AttributeUsage(AttributeTargets.Class)> _
<SecurityPermissionAttribute(SecurityAction.Demand, Flags:=SecurityPermissionFlag.Infrastructure)> _
Public Class RPProxyAttribute
Inherits ProxyAttribute
Public Overrides Function CreateInstance(ByVal Type As Type) As MarshalByRefObject
Dim proxy = New RPProxy(Type)
Dim transparentProxy = DirectCast(proxy.GetTransparentProxy(), MarshalByRefObject)
Return transparentProxy
End Function
End Class
Well, it turns out to be a pretty simple fix, once you work past the god awful ReturnMessage constructor that's quite misleading!
Many thanks to an old colleague of mine, Rich Quackenbush, for taking a few minutes and checking this out. Sometimes, you can't see the forest for the trees!
Anyway, in FieldGetter, I was doing this
ElseIf t.BaseType.Equals(GetType(RPBase)) Then
'---- the field is an OBJECT type field
Dim mc = New MethodCallMessageWrapper(Msg)
'---- create the object
Dim o = Activator.CreateInstance(t)
'---- and construct the return message with that object
Dim r = New ReturnMessage(o, mc.Args, mc.Args.Length, mc.LogicalCallContext, mc)
Return r
Seems completely reasonable, that newly created object being passed into the ReturnMessage constructor argument called ReturnValue.
But no. You actually have to create an object array and pass it is as the 3 element in that array, like this:
ElseIf t.BaseType.Equals(GetType(RPBase)) Then
'---- the field is an OBJECT type field
Dim mc = New MethodCallMessageWrapper(Msg) '---- create the object
Dim o = Activator.CreateInstance(t)
'---- and construct the return message with that object
Dim r = New ReturnMessage(Nothing, New Object() {Nothing, Nothing, o}, 3, mc.LogicalCallContext, mc)
Return r
It turns out, this is because the FieldGetter function is what in being "called" and intercepted by the proxy, and it's signature is
FieldGetter(StringtypeName,StringfieldName,Object&val)
Which, for purposes of constructing a ReturnMessage for that call means that it doesn't have a Returnvalue at all, but rather that the return value is returned as the 3'rd argument in that list.
Since I'm not actually calling the real FieldGetter function, the first two argument (the typename and fieldname) are immaterial, but that 3'rd argument is the proper place to put the return value.
It's always obvious in hindsight!
Many thanks to Rich.
I am trying to write some code that will allow me to dynamically load DLLs into my application, depending on an application setting. The idea is that the database to be accessed is set in the application settings and then this loads the appropriate DLL and assigns it to an instance of an interface for my application to access.
This is my code at the moment:
Dim SQLDataSource As ICRDataLayer
Dim ass As Assembly = Assembly. _
LoadFrom("M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\SQLServer.dll")
Dim obj As Object = ass.CreateInstance(GetType(ICRDataLayer).ToString, True)
SQLDataSource = DirectCast(obj, ICRDataLayer)
MsgBox(SQLDataSource.ModuleName & vbNewLine & SQLDataSource.ModuleDescription)
I have my interface (ICRDataLayer) and the SQLServer.dll contains an implementation of this interface. I just want to load the assembly and assign it to the SQLDataSource object.
The above code just doesn't work. There are no exceptions thrown, even the Msgbox doesn't appear.
I would've expected at least the messagebox appearing with nothing in it, but even this doesn't happen!
Is there a way to determine if the loaded assembly implements a specific interface. I tried the below but this also doesn't seem to do anything!
For Each loadedType As Type In ass.GetTypes
If GetType(ICRDataLayer).IsAssignableFrom(loadedType) Then
Dim obj1 As Object = ass.CreateInstance(GetType(ICRDataLayer).ToString, True)
SQLDataSource = DirectCast(obj1, ICRDataLayer)
End If
Next
EDIT: New code from Vlad's examples:
Module CRDataLayerFactory
Sub New()
End Sub
' class name is a contract,
' should be the same for all plugins
Private Function Create() As ICRDataLayer
Return New SQLServer()
End Function
End Module
Above is Module in each DLL, converted from Vlad's C# example.
Below is my code to bring in the DLL:
Dim SQLDataSource As ICRDataLayer
Dim ass As Assembly = Assembly. _
LoadFrom("M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\SQLServer.dll")
Dim factory As Object = ass.CreateInstance("CRDataLayerFactory", True)
Dim t As Type = factory.GetType
Dim method As MethodInfo = t.GetMethod("Create")
Dim obj As Object = method.Invoke(factory, Nothing)
SQLDataSource = DirectCast(obj, ICRDataLayer)
EDIT: Implementation based on Paul Kohler's code
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetTypes
Dim s As System.Type() = assemblyType.GetInterfaces
For Each ty As System.Type In s
If ty.Name.Contains("ICRDataLayer") Then
MsgBox(ty.Name)
plugin = DirectCast(Activator.CreateInstance(assemblyType), ICRDataLayer)
MessageBox.Show(plugin.ModuleName)
End If
Next
I get the following error with this code:
Unable to cast object of type 'SQLServer.CRDataSource.SQLServer' to type 'DynamicAssemblyLoading.ICRDataLayer'.
The actual DLL is in a different project called SQLServer in the same solution as my implementation code. CRDataSource is a namespace and SQLServer is the actual class name of the DLL.
The SQLServer class implements ICRDataLayer, so I don't understand why it wouldn't be able to cast it.
Is the naming significant here, I wouldn't have thought it would be.
Final Working code
Contents of PluginUtility:
enter code here Public Shared Function GetInstances1(Of Type)(ByVal baseDir As String, ByVal searchPattern As String) As System.Type()
Dim tmpInstances As New List(Of Type)
Try
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetTypes
Dim s As System.Type() = assemblyType.GetInterfaces
Return s.ToArray()
Next
Next
Catch exp As TargetInvocationException
If (Not exp.InnerException Is Nothing) Then
Throw exp.InnerException
End If
End Try
End Function
Code to load the DLL:
enter code here
Dim basedir As String = "M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\"
Dim searchPattern As String = "*SQL*.dll"
Dim plugin As CRDataLayer.ICRDataLayer
Try
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetExportedTypes
If assemblyType.GetInterface("CRDataLayer.ICRDataLayer") IsNot Nothing Then
plugin = DirectCast(Activator.CreateInstance(assemblyType), CRDataLayer.ICRDataLayer)
MessageBox.Show(plugin.ModuleDescription)
End If
Next
Next
Catch exp As TargetInvocationException
If (Not exp.InnerException Is Nothing) Then
Throw exp.InnerException
End If
Catch ex As Exception
MsgBox(ex.Message)
Clipboard.SetText(ex.Message)
End Try
Version 2 - This sample loads up a DLL from it current directory.
There are 2 projects, 1 console application project and a "module" project (the module 'coppies' its DLL to the working directory of the console app).
The sample below simply demonstrates dynamically loading a DLL that implements an interface. The IModule interface just reports its name. PlugInUtility.GetInstances(Of IModule)(Environment.CurrentDirectory, "*.Module.dll") will create an instance of any IModule instance found in a DLL within the current directory ending with ".Module.dll". It's a reflected VB.NET version straight out of Mini SQL Query.
With that in mind something like:
Dim modules As IModule() = PlugInUtility.GetInstances(Of ICRDataLayer)(Environment.CurrentDirectory, "*.Server.dll")
Should satisfy your requirement. Then you just need to chose which one to execute!
The code:
In "VB.LoaderDemo Colsole App"
' IModule.vb
Public Interface IModule
Property ModuleName() As String
End Interface
' PlugInUtility.vb
Imports System.IO
Imports System.Reflection
Public Class PlugInUtility
Public Shared Function GetInstances(Of T)(ByVal baseDir As String, ByVal searchPattern As String) As T()
Dim tmpInstances As New List(Of T)
Try
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As Type
For Each assemblyType In Assembly.LoadFrom(file).GetTypes()
If (Not assemblyType.GetInterface(GetType(T).FullName) Is Nothing) Then
tmpInstances.Add(DirectCast(Activator.CreateInstance(assemblyType), T))
End If
Next
Next
Catch exp As TargetInvocationException
If (Not exp.InnerException Is Nothing) Then
Throw exp.InnerException
End If
End Try
Return tmpInstances.ToArray()
End Function
End Class
' MainModule.vb
Module MainModule
Sub Main()
Dim plugins As IModule() = PlugInUtility.GetInstances(Of IModule)(Environment.CurrentDirectory, "*.Module.dll")
Dim m As IModule
For Each m In plugins
Console.WriteLine(m.ModuleName)
Next
End Sub
End Module
In "Sample1 DLL" (references 'VB.LoaderDemo' for IModule)
Imports VB.LoaderDemo
Public Class MyModule1
Implements IModule
Dim _name As String
Public Sub New()
_name = "Sample 1, Module 1"
End Sub
Public Property ModuleName() As String Implements IModule.ModuleName
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
End Class
The output is:
> Sample 1, Module 1
Is the type ICRDataLayer defined in the DLL you are going to load? If so, you seem to already reference the DLL in your project settings.
You need to work with just reflection:
Dim obj As Object = ass.CreateInstance("ICRDataLayer", True)
Dim t as Type = obj.GetType()
Dim method as MethodInfo = t.GetMethod("DoSomething")
method.Invoke(obj, ...)
Edit: If ICRDataLayer is implemented in the application, and the plugin just implements the interface, you need the plugin to provide a factory for you: (sorry for C# code, I am not familiar with VB.NET's syntax)
// in each of plugins:
static class CRDataLayerFactory // class name is a contract,
{ // should be the same for all plugins
static ICRDataLayer Create()
{
return new CRDataLayerImplementation();
}
}
The application's code should look like this:
Dim factory As Object = ass.CreateInstance("CRDataLayerFactory", True)
Dim t as Type = factory.GetType()
Dim method as MethodInfo = t.GetMethod("Create")
Dim obj as Object = method.Invoke(factory, null)
SQLDataSource = DirectCast(obj, ICRDataLayer)
A few things to look for in your code
Debug through and check that the
assembly is loaded correctly, in case
it fails due to dependency checking
Instead of using GetType, use GetExportedType so you have smaller subset to iterate through
The CreateInstance should use your loadedType rather than the interface (you cant create object from an interface)
Personally, I dont like naming my variable ass, I would shorten it to assem instead :)
I'm developing a VB Web Application in .NET3.5 using Visual Studio 2008.
I'm having difficulty in validating some XML as a string before I add it to a HTML form to post to a 3rd party. I have an XML schema file from the 3rd party to validate against and at this point I'd like the application to perform the validation before each post.
After searching I've found references to a XmlValidatingReader but this is obsolete and I'm having difficulty finding another way to do it.
Also all the good examples are in C# - for now I'm stuck with VB. This is what I have so far which I'm looking for help with!
Public Function ValidateXML(ByVal strXML As String) As Boolean
' er how do I get the schema file into here?
Dim schema As XmlReader
Dim settings As XmlReaderSettings = New XmlReaderSettings()
settings.Schemas.Add("", schema)
settings.ValidationType = ValidationType.Schema
' When I use LoadXML to get the string I can't use the settings object above to get the schema in??
Dim document As XmlDocument = New XmlDocument()
document.LoadXml(strXML)
document.Validate(AddressOf ValidationEventHandler)
End Function
Private Sub ValidationEventHandler(ByVal sender As Object, ByVal e As ValidationEventArgs)
' Gonna return false here but haven't got to it yet! Prob set a variable for use above
End Sub
Thanks
Here's an example:
XmlSchemaValidator in VB.NET
UPDATE - Try this:
Public Function ValidateXML(ByVal strXML As String) As Boolean
Dim xsdPath As String = "path to your xsd"
Dim schema As XmlReader = XmlReader.Create(xsdPath)
Dim document As XmlDocument = New XmlDocument()
document.LoadXml(strXML)
document.Schemas.Add("", schema)
document.Validate(AddressOf ValidationEventHandler)
End Function
This is what I ended up going with
Public validationErrors As String = ""
Public Function ValidPortalRequest(ByVal XMLPortalRequest As String) As Boolean
Try
Dim objSchemasColl As New System.Xml.Schema.XmlSchemaSet
objSchemasColl.Add("xxx", "xxx")
objSchemasColl.Add("xxx", "xxxd")
Dim xmlDocument As New XmlDocument
xmlDocument.LoadXml(XMLPortalRequest)
xmlDocument.Schemas.Add(objSchemasColl)
xmlDocument.Validate(AddressOf ValidationEventHandler)
If validationErrors = "" Then
Return True
Else
Return False
End If
Catch ex As Exception
Throw
End Try
End Function
Private Sub ValidationEventHandler(ByVal sender As Object, ByVal e As ValidationEventArgs)
validationErrors += e.Message & "<br />"
End Sub
Same as Jose's except I've added 2 XSD as a SchemaSet rather than reading them in with an XMLReader.