kevp75
asked on
CallByName Help?
Can someone help me figure this out here.
I am trying to pass some parameters to a CallByName return as the parameters to a function that it should be calling
The function I am trying to run is called Test, and is simply the following:
Public Shared Function Test(ByVal str As String) As String
Return str.ToString()
End Function
The problem I am having is that it should be returning what is passed to it as a parameter, (which is simply the string "This Is A Test"), but nothing is getting displayed to me.
Here's the class doing the work:
I am trying to pass some parameters to a CallByName return as the parameters to a function that it should be calling
The function I am trying to run is called Test, and is simply the following:
Public Shared Function Test(ByVal str As String) As String
Return str.ToString()
End Function
The problem I am having is that it should be returning what is passed to it as a parameter, (which is simply the string "This Is A Test"), but nothing is getting displayed to me.
Here's the class doing the work:
Imports System.Web
Imports System.Text.RegularExpressions
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks
Namespace ZipCM
Public Class Tokenator
Implements System.IDisposable
Private objXml As XDocument
Private _IT As Type = Nothing
Private _Token() As Object
Private _TokenQuery() As Object
Private _Template As String
Public Sub New(ByVal Template As String)
objXml = XDocument.Load(HttpContext.Current.Server.MapPath("/Scripts/Tokens.config"))
Dim _TokenRE As New Regex("\#\#([^&\n]*?)(&.*?)?\#\#")
Dim _RCt As Long = 0
Dim _TokenMatches As MatchCollection = _TokenRE.Matches(Template)
Dim _T(_TokenMatches.Count - 1) As String
Dim _TQ(_TokenMatches.Count - 1) As String
For i As Integer = 0 To _TokenMatches.Count - 1
_T(i) = _TokenMatches(i).Groups(1).Value
_TQ(i) = _TokenMatches(i).Groups(2).Value
Next
_Token = _T
_TokenQuery = _TQ
_Template = Template
Erase _T : Erase _TQ
End Sub
''' <summary>
''' Process out tokens
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Function Tokenator() As String
Dim tmpI As Long
For i As Long = 0 To _Token.GetUpperBound(0)
tmpI = i
Dim _Qry = (From n In objXml...<Token>.AsParallel().WithExecutionMode(ParallelExecutionMode.ForceParallelism) _
Where n.@active = 1 And n.<Name>.Value.Contains(_Token(tmpI)) _
Select n.<Name>, n.<Namespace>, n.<Class>, n.<Property>, n.<Method>, StrValue = n.<String>).ToList()
If _Qry.Count > 0 Then
For Each r In _Qry
If Security.Required(_TokenQuery(i)) Then
'Process the QueryStrings attached to the tokens
Dim _TmpTok = Invoker(r.Method.Value, r.Namespace.Value, r.Class.Value, r.Property.Value, r.StrValue.Value, New Object() {_TokenQuery(i)}) & ":::" & tmpI
_Template = _Template.Replace(r.Name.Value.Replace("##", String.Empty), _TmpTok).Replace(_TokenQuery(i), String.Empty)
Else
Dim _TmpTok = Invoker(r.Method.Value, r.Namespace.Value, r.Class.Value, r.Property.Value, r.StrValue.Value) & ":::" & tmpI
_Template = _Template.Replace(r.Name.Value.Replace("##", String.Empty), _TmpTok)
End If
Next
End If
Next
Return _Template.Replace("##", String.Empty)
End Function
''' <summary>
''' Invoke everything
''' </summary>
''' <param name="MethodName"></param>
''' <param name="NamespaceName"></param>
''' <param name="ClassName"></param>
''' <param name="PropertyName"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Function Invoker(ByVal MethodName As String, Optional ByVal NamespaceName As String = Nothing, Optional ByVal ClassName As String = Nothing, Optional ByVal PropertyName As String = Nothing, Optional ByVal StringValue As String = Nothing, Optional ByVal Params() As Object = Nothing) As String
If (Len(PropertyName) > 0) Then
If (Len(ClassName) > 0) Then
If Not (Len(NamespaceName) > 0) Then
_IT = Type.GetType(ClassName, True, True)
Else
_IT = Type.GetType(NamespaceName & "." & ClassName, True, True)
End If
Else
_IT = Type.GetType(Me.ToString, True, True)
End If
Return CallByName(Activator.CreateInstance(_IT), PropertyName, CallType.Get)
ElseIf Len(StringValue) > 0 Then
Return StringValue
Else
If (Len(ClassName) > 0) Then
If Not (Len(NamespaceName) > 0) Then
_IT = Type.GetType(ClassName, True, True)
Else
_IT = Type.GetType(NamespaceName & "." & ClassName, True, True)
End If
Else
_IT = Type.GetType(Me.ToString, True, True)
End If
If IsNothing(Params) Then
Return CallByName(Activator.CreateInstance(_IT), MethodName, CallType.Get)
Else
Return CallByName(Activator.CreateInstance(_IT), MethodName, CallType.Get, Params)
End If
End If
End Function
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: dispose managed state (managed objects).
End If
Erase _Token
Erase _TokenQuery
_Template = String.Empty
objXml = Nothing
' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
' TODO: set large fields to null.
End If
Me.disposedValue = True
End Sub
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
End Namespace
CallType.Get refers to a property get accessor. What you need is CallType.Method.
ASKER
no luck. Changed it to Method, and still nothing is returned
why not use the CallByName function directly?
http://msdn.microsoft.com/en-us/library/chsc1tx6%28v=vs.71%29.aspx
http://msdn.microsoft.com/en-us/library/chsc1tx6%28v=vs.71%29.aspx
This is the over-simplified test version i am using, which works, so the logic is sound.
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
Dim _IT As Type
_IT = Type.GetType("WebApplicationVB.WebForm1", True, True)
Dim s As String = CallByName(Activator.CreateInstance(_IT), "DoSomething", CallType.Method, New Object() {"Hello World"})
End Sub
Public Shared Function DoSomething(ByVal str As String) As String
Return str
End Function
Is it retrieving the Type into _IT correctly?
ASKER
Yes. Type is retrieving correctly
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
hmm... my issue appears to be deeper than this.
Once I replace the New Object() {_TokenQuery(i)} with the New Object() {"Hello World"}
I get the Hello World.
Once I replace the New Object() {_TokenQuery(i)} with the New Object() {"Hello World"}
I get the Hello World.
ASKER
but...when I set the breakpoint on that line... it shows me the value of _TokenQuery(i)...
ASKER
@angelIII I would, but I need to be able to fireoff stuff from any namespace.class.method, etc...
OK. I've expanded my test scenario a little to sort of replicate your arrays:
Dim _T(1) As String
_T(0) = "Hello World"
Dim _Token() As Object
_Token = _T
Dim _IT As Type
_IT = Type.GetType("WebApplicationVB.WebForm1", True, True)
Dim s As String = CallByName(Activator.CreateInstance(_IT), "DoSomething", CallType.Method, New Object() {_Token(0)})
And I am still getting "Hello World" back. Which may point to an issue with the way you are populating the "_Token" array.
ASKER
well. _Token populates fine, and at the same time _TokenQuery populates.
so they have equal bounds.
I have verified, that I can get the value of _TokenQuery(i), that is until it hits Line 51 (above). once it hits that it disappears
so they have equal bounds.
I have verified, that I can get the value of _TokenQuery(i), that is until it hits Line 51 (above). once it hits that it disappears
Does it work ok if you pass a hard-coded value instead of _TokenQuery(i)?
ASKER
Yes.
If I hardcode in New Object() {"Hello World"}
It passes. I would normally say that the array is not being filled right, however, when I set a break point to the line before the CallByName, and simply assign the _TokenQuery(i) to a variable, I can see the value that it should be passing. (as in the screenshot above).
Could it be because some of the values in the _TokenQuery() array are empty strings?... I populate both _Token and _TokenQuery at the same time to make sure the indexes (spelling) line up right.
If I hardcode in New Object() {"Hello World"}
It passes. I would normally say that the array is not being filled right, however, when I set a break point to the line before the CallByName, and simply assign the _TokenQuery(i) to a variable, I can see the value that it should be passing. (as in the screenshot above).
Could it be because some of the values in the _TokenQuery() array are empty strings?... I populate both _Token and _TokenQuery at the same time to make sure the indexes (spelling) line up right.
I wouldn't have thought so. Null/Nothing might cause a problem, but I can't see any reason why an empty string should. So, if you assign it to a variable, and pass that variable to CallByName does it work ok?
ASKER
Still nothing. I am even making sure now that the empty _TokenQuery is ""
I assign it to a variable, the variable gets populated, but nothing comes from it once it hits CallByName
I assign it to a variable, the variable gets populated, but nothing comes from it once it hits CallByName
Do you have a sample of what your Tokens.config files contains? That way I can replicate precisely what you have.
ASKER
sure:
<?xml version="1.0"?>
<Tokens>
<Token active="1">
<Name><![CDATA[##TEST1##]]></Name>
<Namespace>ZipCM</Namespace>
<Class>Settings</Class>
<Property><![CDATA[SiteID]]></Property>
<Method><![CDATA[]]></Method>
<String><![CDATA[]]></String>
</Token>
<Token active="1">
<Name><![CDATA[##TEST2##]]></Name>
<Namespace>ZipCM</Namespace>
<Class>SiteMap</Class>
<Property><![CDATA[]]></Property>
<Method><![CDATA[SiteMapXml]]></Method>
<String><![CDATA[]]></String>
</Token>
<Token active="1">
<Name><![CDATA[##TEST3##]]></Name>
<Namespace>ZipCM</Namespace>
<Class>Settings</Class>
<Property><![CDATA[SitePath]]></Property>
<Method><![CDATA[]]></Method>
<String><![CDATA[]]></String>
</Token>
<Token active="1">
<Name><![CDATA[##TEST4##]]></Name>
<Namespace></Namespace>
<Class>Common</Class>
<Property><![CDATA[]]></Property>
<Method><![CDATA[Test]]></Method>
<String><![CDATA[]]></String>
</Token>
<Token active="1">
<Name><![CDATA[##TEST5##]]></Name>
<Namespace></Namespace>
<Class></Class>
<Property><![CDATA[]]></Property>
<Method><![CDATA[]]></Method>
<String><![CDATA[This is just a simple string replacement]]></String>
</Token>
</Tokens>
Forgot one vital part. Do you have a sample of what "template" will contain?
ASKER
:) sure:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim _Template = "<div>" & _
" <h1>##TEST1&ID=123&bob=yahoo&email=oioiujij##</h1>" & _
" <h1>##TEST2##</h1>" & _
" <h1>##TEST3##</h1>" & _
" <h1>##TEST4&ID=123&a=1&b=2&c=3&d=4##</h1>" & _
" <h1>##TEST5##</h1>" & _
"</div>"
Using objTok As New ZipCM.Tokenator(_Template)
With objTok
Response.Write(.Tokenator())
End With
End Using
End Sub
Hmm, weird, it seems to be working fine for me. In so much as it returns "&ID=123&bob=yahoo&email=o ioiujij" from the method call.
ASKER
can you post your code so I can see how it differs from mine?
Class:
Imports System.Linq
Namespace ZipCM
Public Class Tokenator
Implements System.IDisposable
Private objXml As XDocument
Private _IT As Type = Nothing
Private _Token() As Object
Private _TokenQuery() As Object
Private _Template As String
Public Sub New(ByVal Template As String)
objXml = XDocument.Load(HttpContext.Current.Server.MapPath("/Scripts/Tokens.config"))
Dim _TokenRE As New Regex("\#\#([^&\n]*?)(&.*?)?\#\#")
Dim _RCt As Long = 0
Dim _TokenMatches As MatchCollection = _TokenRE.Matches(Template)
Dim _T(_TokenMatches.Count - 1) As String
Dim _TQ(_TokenMatches.Count - 1) As String
For i As Integer = 0 To _TokenMatches.Count - 1
_T(i) = _TokenMatches(i).Groups(1).Value
_TQ(i) = _TokenMatches(i).Groups(2).Value
Next
_Token = _T
_TokenQuery = _TQ
_Template = Template
Erase _T : Erase _TQ
End Sub
''' <summary>
''' Process out tokens
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Function Tokenator() As String
Dim tmpI As Long
For i As Long = 0 To _Token.GetUpperBound(0)
tmpI = i
Dim _Qry = (From n In objXml...<Token>.AsParallel().WithExecutionMode(ParallelExecutionMode.ForceParallelism) _
Where n.@active = 1 And n.<Name>.Value.Contains(_Token(tmpI)) _
Select n.<Name>, n.<Namespace>, n.<Class>, n.<Property>, n.<Method>, StrValue = n.<String>).ToList()
If _Qry.Count > 0 Then
For Each r In _Qry
Dim _TmpTok = Invoker(r.Method.Value, r.Namespace.Value, r.Class.Value, r.Property.Value, r.StrValue.Value, New Object() {_TokenQuery(i)}) & ":::" & tmpI
_Template = _Template.Replace(r.Name.Value.Replace("##", String.Empty), _TmpTok).Replace(_TokenQuery(i), String.Empty)
Next
End If
Next
Return _Template.Replace("##", String.Empty)
End Function
''' <summary>
''' Invoke everything
''' </summary>
''' <param name="MethodName"></param>
''' <param name="NamespaceName"></param>
''' <param name="ClassName"></param>
''' <param name="PropertyName"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Function Invoker(ByVal MethodName As String, Optional ByVal NamespaceName As String = Nothing, Optional ByVal ClassName As String = Nothing, Optional ByVal PropertyName As String = Nothing, Optional ByVal StringValue As String = Nothing, Optional ByVal Params() As Object = Nothing) As String
If (Len(PropertyName) > 0) Then
If (Len(ClassName) > 0) Then
If Not (Len(NamespaceName) > 0) Then
_IT = Type.GetType(ClassName, True, True)
Else
_IT = Type.GetType(NamespaceName & "." & ClassName, True, True)
End If
Else
_IT = Type.GetType(Me.ToString, True, True)
End If
Return CallByName(Activator.CreateInstance(_IT), PropertyName, CallType.Get)
ElseIf Len(StringValue) > 0 Then
Return StringValue
Else
If (Len(ClassName) > 0) Then
If Not (Len(NamespaceName) > 0) Then
_IT = Type.GetType(ClassName, True, True)
Else
_IT = Type.GetType(NamespaceName & "." & ClassName, True, True)
End If
Else
_IT = Type.GetType(Me.ToString, True, True)
End If
If IsNothing(Params) Then
Return CallByName(Activator.CreateInstance(_IT), MethodName, CallType.Get)
Else
Return CallByName(Activator.CreateInstance(_IT), MethodName, CallType.Get, Params)
End If
End If
End Function
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: dispose managed state (managed objects).
End If
Erase _Token
Erase _TokenQuery
_Template = String.Empty
objXml = Nothing
' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
' TODO: set large fields to null.
End If
Me.disposedValue = True
End Sub
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
End Namespace
Page with dummy method:Imports System.Data
Imports System.Data.OleDb
Imports System.Linq
Public Class _Default
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim _Template = "<div>" & _
" <h1>##TEST1&ID=123&bob=yahoo&email=oioiujij##</h1>" & _
" <h1>##TEST2##</h1>" & _
" <h1>##TEST3##</h1>" & _
" <h1>##TEST4&ID=123&a=1&b=2&c=3&d=4##</h1>" & _
" <h1>##TEST5##</h1>" & _
"</div>"
Using objTok As New ZipCM.Tokenator(_Template)
With objTok
Response.Write(.Tokenator())
End With
End Using
End Sub
Public Function DoStuff(ByVal value As String) As String
Return value & "modified"
End Function
End Class
Tokens file:<?xml version="1.0" encoding="utf-8" ?>
<Tokens>
<Token active="1">
<Name><![CDATA[##TEST1##]]></Name>
<Namespace>WebApplication1</Namespace>
<Class>_Default</Class>
<Property><![CDATA[]]></Property>
<Method><![CDATA[DoStuff]]></Method>
<String><![CDATA[]]></String>
</Token>
<Token active="1">
<Name><![CDATA[##TEST2##]]></Name>
<Namespace>WebApplication1</Namespace>
<Class>_Default</Class>
<Property><![CDATA[]]></Property>
<Method><![CDATA[DoStuff]]></Method>
<String><![CDATA[]]></String>
</Token>
<Token active="1">
<Name><![CDATA[##TEST3##]]></Name>
<Namespace>WebApplication1</Namespace>
<Class>_Default</Class>
<Property><![CDATA[]]></Property>
<Method><![CDATA[DoStuff]]></Method>
<String><![CDATA[]]></String>
</Token>
<Token active="1">
<Name><![CDATA[##TEST4##]]></Name>
<Namespace>WebApplication1</Namespace>
<Class>_Default</Class>
<Property><![CDATA[]]></Property>
<Method><![CDATA[DoStuff]]></Method>
<String><![CDATA[]]></String>
</Token>
<Token active="1">
<Name><![CDATA[##TEST5##]]></Name>
<Namespace>WebApplication1</Namespace>
<Class>_Default</Class>
<Property><![CDATA[]]></Property>
<Method><![CDATA[DoStuff]]></Method>
<String><![CDATA[This is just a simple string replacement]]></String>
</Token>
</Tokens>
ASKER
The only thing I can see different is that my Method "Test" comes from a class library...
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
well... the whole point is so it's dynamic... but for this purpose I will try that manually.
ASKER
ok. It works if I do this:
For i As Integer = 0 To _TokenMatches.Count - 1
_T(i) = _TokenMatches(i).Groups(1) .Value
_TQ(0) = "&email=bob@yahoo.com"
_TQ(3) = "&a=123"
'If _TokenMatches(i).Groups(2) .Value IsNot Nothing Then
' _TQ(i) = "&email=bob@yahoo.com" '_TokenMatches(i).Groups(2 ).Value
'Else
' _TQ(i) = ""
'End If
Next
For i As Integer = 0 To _TokenMatches.Count - 1
_T(i) = _TokenMatches(i).Groups(1)
_TQ(0) = "&email=bob@yahoo.com"
_TQ(3) = "&a=123"
'If _TokenMatches(i).Groups(2)
' _TQ(i) = "&email=bob@yahoo.com" '_TokenMatches(i).Groups(2
'Else
' _TQ(i) = ""
'End If
Next
ASKER
ready for this one. It DOES NOT, and I repeat DOES NOT pull the data from the hardcoded _TQ, instead it now does the replacing correctly as it should from the token.config file....
make sense outta that one? :(
make sense outta that one? :(
ASKER
to reiterate... this:
does not return the values assigned.... it now returns the values attached to the tokens in the _Template variable
Public Sub New(ByVal Template As String)
objXml = XDocument.Load(HttpContext.Current.Server.MapPath("/Scripts/Tokens.config"))
Dim _TokenRE As New Regex("\#\#([^&\n]*?)(&.*?)?\#\#")
Dim _RCt As Long = 0
Dim _TokenMatches As MatchCollection = _TokenRE.Matches(Template)
Dim _T(_TokenMatches.Count - 1) As String
Dim _TQ(_TokenMatches.Count - 1) As String
For i As Integer = 0 To _TokenMatches.Count - 1
_T(i) = _TokenMatches(i).Groups(1).Value
_TQ(0) = "&email=bob@yahoo.com"
_TQ(3) = "&a=123"
'If _TokenMatches(i).Groups(2).Value IsNot Nothing Then
' _TQ(i) = "&email=bob@yahoo.com" '_TokenMatches(i).Groups(2).Value
'Else
' _TQ(i) = ""
'End If
Next
_Token = _T
_TokenQuery = _TQ
_Template = Template
Erase _T : Erase _TQ
End Sub
does not return the values assigned.... it now returns the values attached to the tokens in the _Template variable
ASKER
so, I am extremely confused now. When I hard code (0), etc to a value... doesn;t matter what the value is, it will grab the correct query from the token.config... but when I try to dynamically fill it, the whole thing bombs out...
Public Sub New(ByVal Template As String)
objXml = XDocument.Load(HttpContext .Current.S erver.MapP ath("/Scri pts/Tokens .config"))
Dim _TokenRE As New Regex("(?<=##)([^&\n]*?)(& .*?)?(?=## )")
Dim _RCt As Long = 0
Dim _TokenMatches As MatchCollection = _TokenRE.Matches(Template)
Dim _T(_TokenMatches.Count - 1) As String
Dim _TQ(_TokenMatches.Count - 1) As String
For i As Integer = 0 To _TokenMatches.Count - 1
_T(i) = _TokenMatches(i).Groups(1) .Value
'_TQ(0) = " "
'_TQ(3) = " "
'_TQ(4) = " "
If Not (Security.Required(_TokenM atches(i). Groups(2). Value)) Then
_TQ(i) = " "
Else
_TQ(i) = Nothing
End If
Next
_Token = _T
_TokenQuery = _TQ
_Template = Template
Erase _T : Erase _TQ
End Sub
Public Sub New(ByVal Template As String)
objXml = XDocument.Load(HttpContext
Dim _TokenRE As New Regex("(?<=##)([^&\n]*?)(&
Dim _RCt As Long = 0
Dim _TokenMatches As MatchCollection = _TokenRE.Matches(Template)
Dim _T(_TokenMatches.Count - 1) As String
Dim _TQ(_TokenMatches.Count - 1) As String
For i As Integer = 0 To _TokenMatches.Count - 1
_T(i) = _TokenMatches(i).Groups(1)
'_TQ(0) = " "
'_TQ(3) = " "
'_TQ(4) = " "
If Not (Security.Required(_TokenM
_TQ(i) = " "
Else
_TQ(i) = Nothing
End If
Next
_Token = _T
_TokenQuery = _TQ
_Template = Template
Erase _T : Erase _TQ
End Sub
ASKER
sorry. the regex is wrong in the post above this. it should read: \#\#([^&\n]*?)(&.*?)?\#\#
ASKER
got it.
I was checking if the match on the second group would produce a nothing, but I should have also included a check for an empty string, once I added that in to populate the _TQ array, it works
Thanks for the help with this one.!!!
I was checking if the match on the second group would produce a nothing, but I should have also included a check for an empty string, once I added that in to populate the _TQ array, it works
Thanks for the help with this one.!!!