I have a bit of code in a WebQueryOpen agent, which loops a field called "Members", which stores a list of Notes-style user names and prints to the browser their name in a formatted style. The code is very simply:
Set item = web.document.GetFirstItem("dspMembers") Forall v In web.document.GetFirstItem("Members").values Call item.AppendToTextList( "<li>"+GetUserDetails( Cstr(v), "Formal" ) +"</li>") End Forall
No prizes for working out what those does. For each member listed in the document it adds a bullet point to the displayed list of members. How the name of the user is displayed is governed by a separate function.
This GetUserDetails() function is a bit like an extended @NameLookup for LotusScript. I keep it in my "CommonRoutines" Script Library and it's accessible from all my agents. It looks like this:
Function GetUserDetails(username As String, detail As String) As String Dim uname As NotesName Dim userDoc As NotesDocument Dim userView as NotesView Set uname = New NotesName(username) If web.directory.IsOpen Then 'web.directory is "names.nsf" Set userView = web.directory.getView("($VIMPeople)") If Not userView Is Nothing Then Set userdoc = userView.GetDocumentByKey(uname.Abbreviated, True) If Not userdoc Is Nothing Then If detail = "Long" Then GetUserDetails = userdoc.Salutation(0) _ + " " + Left(userdoc.FirstName(0), 1) + " " + userdoc.Lastname(0) _ +", " + userdoc.CompanyName(0) + "<br />"+userdoc.OfficePhoneNumber(0) _ +"<br /><a href=""mailto:"+userdoc.MailAddress(0)+""">"+userdoc.MailAddress(0)+"</a>" Elseif Lcase(detail) = "formal" Then GetUserDetails = userdoc.Salutation(0) + " " + Left(userdoc.FirstName(0), 1) + " " + userdoc.Lastname(0) Elseif Lcase(detail) = "fullname" Then GetUserDetails = userdoc.Salutation(0) + " " + userdoc.FirstName(0) + " " + userdoc.Lastname(0) Else 'Unknown format. Must want field value? If userdoc.HasItem(detail) Then GetUserDetails = userdoc.GetItemValue(detail)(0) Else GetUserDetails = uname.Abbreviated End If End If Else GetUserDetails = uname.Abbreviated End If Else GetUserDetails = uname.Abbreviated End If Else GetUserDetails = uname.Abbreviated End If End Function
The idea is that, given a name like Jake Howlett/ROCKALL it uses the address book to return a name in the form Mr J Howlett, Rockall Design ltd, Nottingham. Or you can just use it to get a field's value by name. If for any reason it can't find the user document or work out what to return it just returns the user name in abbreviated form.
It all works well, but, after not very long I noticed the WQO agent which used it was taking longer and longer to run. The slowness of the WQO was directly proportional to the number of Members. Most of you can probably see why. If not, then the title of this page should give you a clue.
The problem with my code is, of course, that I'm repeatedly calling the getView() method. Consider this from Julian's list of preformance tips:
If you need to use a reference to a view multiple times in your code, get the view only once and share the reference (either using a global or static variable, or by passing a NotesView object as a parameter in functions/subs/methods). Accessing views using getView is a very expensive operation
It turned out that each call to web.directory.getView("($VIMPeople)") was taking 0.3s. For 100 members that means it takes way, way too long to open. Remember no web page should take longer than 7s to open!
So, taking Julian's advice I turned the user view in the directory in to a global variable as part of the WebSession class. Agents that were taking 20 seconds or more to load are now taking less than one!
I had no idea this was such bad practice. More than ten years with Notes and I'm still learning the basics...