Link to home
Start Free TrialLog in
Avatar of kevp75
kevp75Flag for United States of America

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:
 
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

Open in new window

Avatar of Carl Tawn
Carl Tawn
Flag of United Kingdom of Great Britain and Northern Ireland image

CallType.Get refers to a property get accessor. What you need is CallType.Method.
Avatar of kevp75

ASKER

no luck.   Changed it to Method, and still nothing is returned
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

Open in new window

Is it retrieving the Type into _IT correctly?
Avatar of kevp75

ASKER

Yes.  Type is retrieving correctly
ASKER CERTIFIED SOLUTION
Avatar of Carl Tawn
Carl Tawn
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of kevp75

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.
Avatar of kevp75

ASKER

but...when I set the breakpoint on that line...  it shows me the value of _TokenQuery(i)...
Avatar of kevp75

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)})

Open in new window

And I am still getting "Hello World" back. Which may point to an issue with the way you are populating the "_Token" array.
Avatar of kevp75

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
Avatar of kevp75

ASKER

screenshot User generated image
Does it work ok if you pass a hard-coded value instead of _TokenQuery(i)?
Avatar of kevp75

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.
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?
Avatar of kevp75

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
Do you have a sample of what your Tokens.config files contains? That way I can replicate precisely what you have.
Avatar of kevp75

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>

Open in new window

Forgot one vital part. Do you have a sample of what "template" will contain?
Avatar of kevp75

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

Open in new window

Hmm, weird, it seems to be working fine for me. In so much as it returns "&ID=123&bob=yahoo&email=oioiujij" from the method call.
Avatar of kevp75

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

Open in new window

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

Open in new window

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>

Open in new window

Avatar of kevp75

ASKER

The only thing I can see different is that my Method "Test" comes from a class library...
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of kevp75

ASKER

well...  the whole point is so it's dynamic...  but for this purpose I will try that manually.
Avatar of kevp75

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
Avatar of kevp75

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?   :(
Avatar of kevp75

ASKER

to reiterate...  this:
 
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

Open in new window


does not return the values assigned....  it now returns the values attached to the tokens in the _Template variable
Avatar of kevp75

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.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) = " "
                '_TQ(3) = " "
                '_TQ(4) = " "
                If Not (Security.Required(_TokenMatches(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

Avatar of kevp75

ASKER

sorry.   the regex is wrong in the post above this.  it should read: \#\#([^&\n]*?)(&.*?)?\#\#
Avatar of kevp75

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.!!!