VB.Net

VB.Net 2.0, SQL Server 2000 & Windows Application SQL Error

Today, I started working on an application to perform bulk changes to our Deltek Vision database to change tasks, sub-tasks, budgets and billing terms. So, as I go to write the SQL connection string, something I have done 100s of times, I kept getting the following error from my app:

An error has occurred while establishing a connection to the server. When connecting to SQL Server 2005, this failure may be caused by the fact that under the default settings SQL Server does not allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)

While the error is pretty descriptive, there is one slight problem - I'm not trying to access a 2005 SQL Server, but a SQL Server 2000 box. So, I do what any good programmer does - he searches the major search engines for a solution, but most of the examples are of users trying to 1) build a Web application and have a web.config error or 2) are actually trying to access a SQL Server 2005 database. Yikes, now what?

I can't stress this enough - check your connection string. I was actually passing a blank Data Source (I was using SelectedValue as opposed to SelectedItem) and since I have SQLExpress running on my development machine, I assume that's why I was generating a 2005 error when trying, in theory, to connect to a SQL 2000 machine. The lesson is - verify your connection string when getting this error and trying to access a SQL 2000 machine. If you're trying to access a SQL 2005 machine, follow the enabling remote connections info that you'll find on the hundreds of pages that come up in he search engines for this error.

Convert .Net Code to HTML

When you're writing a development related blog, you're eventually (hopefully) going to write some code snippets that you want to share with your readers. However, in order to get the most out of that code snippet, you should make it easy to read and color coded so that potential users can quickly read through your code and evaluate its worth.

That's where CopySourceAsHTML will solve all your problems. CSAH is a plug-in that integrates directly into your Visual Studio IDE environment and allows you to highlight code, right click and choose "Copy As HTML". The tool is freeware and performs exceptionally - if you maintain a .Net developer blog, I would suggest installing this add-on.

SharePoint v3: Quick Launch Update

Just a FYI to the 3 of you reading this site (Hi Mom and Dad!), I made an update to the Recreating the SharePoint Quick Launch story I posted back in February. I made some code fixes that were mainly introduced with the release of the 40 Free WSS Application Templates made by Microsoft.

Hope the bug fixes help!

VB.Net - How to Unlock a Domain Account in Active Directory

How to Unlock a Domain Account in Active Directory utilizing Visual Basic .Net - (note: you must have Domain Admin privledges to execute this code successfully and you must import the System.DirectoryServices namespace):

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim strError As String
Try
Dim child As New System.DirectoryServices.DirectoryEntry("LDAP://DC=YourDomainsName,DC=com")
Dim searcher As New DirectorySearcher(child)
Dim result As SearchResult
Dim userEntry As DirectoryEntry
searcher.Filter = "(SAMAccountName=TheUsernameYouWantDisabled)"
searcher.CacheResults = False
result = searcher.FindOne
userEntry = result.GetDirectoryEntry
With userEntry
userEntry.Properties("LockOutTime").Value = 0
End With
userEntry.CommitChanges()
Catch ex As Exception
strError = ex.ToString
End Try

End Sub

VB.Net - How to Disable a Domain Account in Active Directory

How to Disable a Domain Account in Active Directory utilizing Visual Basic .Net - (note: you must have Domain Admin privledges to execute this code successfully and you must import the System.DirectoryServices namespace):

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim strError As String
Try
Dim child As New System.DirectoryServices.DirectoryEntry("LDAP://DC=YourDomainsName,DC=com")
Dim searcher As New DirectorySearcher(child)
Dim result As SearchResult
Dim userEntry As DirectoryEntry
searcher.Filter = "(SAMAccountName=TheUsernameYouWantDisabled)"
searcher.CacheResults = False
result = searcher.FindOne
userEntry = result.GetDirectoryEntry
With userEntry
userEntry.NativeObject.accountdisabled = True
End With
userEntry.CommitChanges()
Catch ex As Exception
strError = ex.ToString
End Try

End Sub

Visual Basic .Net Coding Samples

Below are code samples utilizing Visual Basic .Net. If you have any questions, comments or corrections on any code sample, please email me at hagrin at gmail dot com and I'll try and get back to all user inquiries as soon as possible. Thank you and hopefully this code will proove to be helpful.

Disable a Domain Account in Active Directory
Unlock a Domain Account in Active Directory

SharePoint v3: Recreating the Quick Launch Menu

UPDATE: 2007 May 2nd - I've updated this article to include a lot of bug fixes that I have encountered along the way. I will maintain some type of versioning at the end of this post so readers can follow code changes that have occurred over time.

Microsoft's SharePoint Services 2007 (v3) provides so many additional features and bug fixes to their previous version that I was extremely anxious to upgrade our company's intranet to the newer code. However, as with any upgrade, you eventually run into stumbling blocks that will make your life miserable as a programmer/designer.

I recently came across one such issue with SharePoint Services 2007 - when you create a new page through the front-end, the Quick Launch menu is lost. Huh?

The Quick Launch menu is the standard left side navigation module that holds link information. In addition to the site specific links that you add to the Quick Launch, a static "View All Site Content" link is docked at the top of this list (which allows users to see a listing of all the Lists, Document Libraries, Picture Libraries, Surveys, Discussions and more. The items displayed in the quick launch are managed through the "Site Settings" option underneath the "Site Actions" button.

However, there is one major problem with the default SharePoint implementaion - when a user creates a new page (whether a basic or web part page), the Quick Launch menu does not attach itself to that new page. For some unknown reason, a major navigational module is dropped from secondary pages created through the SharePoint front-end. I would say that this decision is dubious at best. Since our company wanted to dock our Quick Launch onto every new page created on every site we maintain, we needed to programmatically come up with a solution. I decided to solve this problem by recreating the Quick Launch as a custom web part.

How do you reconstruct the Quick Launch from scratch? First, as with most advanced custom SharePoint tasks, you need to understand how the database is structured. Many SharePoint admins will tell you to "leave the SharePoint database alone", but simple reads to the database will not cause a problem (in fact, as long as you understand the database structure, (although not supported) I have created procedures that update the SharePoint database directly by pulling information from other data sources). The Quick Launch information is stored in two tables - Webs and NavNodes. The Webs table stores information concerning the different sites that have been created. It's important to first pull the 'id' for the for the site the user is currently browsing.

select id, fullurl from webs where siteid = 'root_site_id' and fullurl = 'site_user_is_on'

How do you tell what site a user is on? One such method would be to get the URL through Page.Request.Url.AbsoluteUri, then get the array(3) value and use that value for the 'fullurl' where clause(and if your dataset = 0 rows, you are on the default site, otherwise you are on a subsite). One problem with this method is that you cannot have a Document Library that shares the same name as a subsite (however, this is the option we implemented for now until I develop something better). Next, you take that 'id' value and query the NavNodes table for the record containing the root Quick Launch information for that site. You'll grab the 'eid' value for that record and then use that value to grab all the records where that eid value is found in the 'eidparent' column (for that root site and subsite).

select eid, numchildren, rankchild, url, name from navnodes where eidparent in (select eid from navnodes where webid = 'subsite_id' and siteid = 'root_site_id' and name = 'Quick Launch') and webid = 'subsite_id' and siteid = 'root_site_id' order by rankchild

This will give you all the "Link Headings" for that site's Quick Launch. Read these values into an array. First, render these headings using the ms-navheader class. Before moving onto the next "Link Heading", we must check to see if there are any "children" or "Link Items" for this heading. That would be done by running the following query:

select eid, numchildren, rankchild, url, name from navnodes where eidparent in (select eid from navnodes where eid = 'link_heading_eid' and webid = 'subsite_id' and siteid = 'root_site_id') and webid = 'subsite_id' and siteid = 'root_site_id' order by rankchild

If your dataset count is > 0, then read these "Link Items" into an array and render them all out while applying the ms-navitem class. Once all the "Link Items" are printed out, move to the next "Link Heading" until you have read and rendered all headings. So, there's the logic behind recreating the Quick Launch. Here's a snippet of some of the code I used to render my Quick Launch recreation (GUIDs changed to protect the innocent):

   41         Try

   42             strURL = Page.Request.Url.AbsoluteUri

   43             arrURL = Split(strURL, "/", -1, CompareMethod.Text)

   44 

   45 #If PROD = "Intranet" Then

   46             strRootGUID = "{035AA977-25EF-4B20-AFF4-3BBF028CCE6C}"

   47             strRootURL = "intranet.domain.com"

   48             SQLConnection.ConnectionString = db.GetDBShare3Intranet

   49 #ElseIf PROD = "Extranet" Then

   50             strRootGUID = "{6B052A1E-F7FE-4A42-849F-A55079A49E3A}"

   51             strRootURL = "portal.domain.com"

   52             SQLConnection.ConnectionString = db.GetDBShare3Extranet

   53 #ElseIf PROD = "Development" Then

   54             strRootGUID = ""

   55             strRootURL = "development:16542"

   56             SQLConnection.ConnectionString = ""

   57 #End If

   58 

   59             SQLConnection.Open()

   60             SQLQuery = "select id, fullurl from webs where siteid = '" & strRootGUID & "' and fullurl = '" & arrURL(3) & "'"

   61             Dim DataAdapter As SqlClient.SqlDataAdapter = New SqlClient.SqlDataAdapter(SQLQuery, SQLConnection)

   62             DataAdapter.Fill(DataSet)

   63 

   64             If DataSet.Tables(0).Rows.Count > 0 Then

   65                 ' Match made - we are on a subsite

   66                 GUID = DataSet.Tables(0).Rows(i).Item(0)

   67                 strGUID = GUID.ToString

   68                 arrURL(3) = arrURL(3)

   69             Else

   70                 ' No match made - we are on the Root Site

   71 

   72 #If PROD = "Intranet" Then

   73                 strGUID = "{01872F73-68B8-44EC-AE6E-E0FCCF231AB5}"

   74 #ElseIf PROD = "Extranet" Then

   75                 strGUID = "{E3DB7959-A1A7-4619-AC7D-F0B4E67D2DC6}"

   76 #ElseIf PROD = "Development" Then

   77                 strGUID = ""

   78 #End If

   79 

   80                 arrURL(3) = ""

   81             End If

   82 

   83             DataSet = New DataSet

   84             SQLQuery = "select eid, numchildren, rankchild, url, name, siteid from navnodes where eidparent in (select eid from navnodes where webid = '" & strGUID & "' and siteid = '" & strRootGUID & "' and name = 'Quick Launch') and webid = '" & strGUID & "' and siteid = '" & strRootGUID & "' order by rankchild"

   85             DataAdapter = New SqlClient.SqlDataAdapter(SQLQuery, SQLConnection)

   86             DataAdapter.Fill(DataSet)

   87 

   88             If DataSet.Tables(0).Rows.Count > 0 Then

   89                 output.RenderBeginTag("div class=ms-quicklaunchouter")

   90                 output.RenderBeginTag("div class=ms-quicklaunch style=" & Chr(&H22) & "width:100%; border: none;" & Chr(&H22))

   91                 output.RenderBeginTag("table cellpadding=0 cellspacing=0 class=ms-quicklaunch width=100%")

   92                 output.RenderBeginTag("tr")

   93                 output.RenderBeginTag("td class=ms-quicklaunchheader style=" & Chr(&H22) & "border: none;" & Chr(&H22))

   94                 output.Write("Navigation")

   95                 output.RenderEndTag()

   96                 output.RenderEndTag()

   97 

   98                 For i = 0 To DataSet.Tables(0).Rows.Count - 1

   99                     output.RenderBeginTag("tr")

  100                     output.RenderBeginTag("td class=ql-navheader")

  101                     ListGUID = DataSet.Tables(0).Rows(i).Item(5)

  102                     strListGUID = ListGUID.ToString

  103 

  104                     ' Start adding exception handling ...

  105                     ' 1) Links that start with http:// shouldn't append to the root.

  106 

  107                     If Left(DataSet.Tables(0).Rows(i).Item(3), 7) = "http://" Then

  108                         output.RenderBeginTag("a class=ms-navheader href=" & System.Web.HttpUtility.UrlPathEncode(DataSet.Tables(0).Rows(i).Item(3)))

  109                     Else

  110                         ' Write the "nomral" quick launch URL scheme

  111                         output.RenderBeginTag("a class=ms-navheader href=http://" & strRootURL & System.Web.HttpUtility.UrlPathEncode(DataSet.Tables(0).Rows(i).Item(3)))

  112                     End If

  113                     output.RenderBeginTag("b")

  114                     output.Write(DataSet.Tables(0).Rows(i).Item(4))

  115                     output.RenderEndTag()

  116                     output.RenderEndTag()

  117                     output.RenderEndTag()

  118                     output.RenderEndTag()

  119 

  120                     If DataSet.Tables(0).Rows(i).Item(1) > 0 Then

  121                         ' There are child items for this menu item

  122 

  123                         DataSet2 = New DataSet

  124                         SQLQuery = "select eid, numchildren, rankchild, url, name, DocID from navnodes where eidparent in (select eid from navnodes where eid = '" & DataSet.Tables(0).Rows(i).Item(0) & "' and webid = '" & strGUID & "' and siteid = '{035AA977-25EF-4B20-AFF4-3BBF028CCE6C}') and webid = '" & strGUID & "' and siteid = '{035AA977-25EF-4B20-AFF4-3BBF028CCE6C}' order by rankchild"

  125                         DataAdapter = New SqlClient.SqlDataAdapter(SQLQuery, SQLConnection)

  126                         DataAdapter.Fill(DataSet2)

  127 

  128                         For x = 0 To DataSet2.Tables(0).Rows.Count - 1

  129                             output.RenderBeginTag("tr")

  130                             output.RenderBeginTag("td")

  131                             output.RenderBeginTag("table class=ms-navitem width=100% border=0 cellpadding=0 cellspacing=0")

  132                             output.RenderBeginTag("tr")

  133                             output.RenderBeginTag("td width=100% style=" & Chr(&H22) & "border: none;" & Chr(&H22))

  134 

  135                             If IsDBNull(DataSet2.Tables(0).Rows(x).Item(3)) = False Then

  136                                 ' URL field in NavNodes has a value

  137                                 output.RenderBeginTag("a class=ms-navitem href=http://" & strRootURL & System.Web.HttpUtility.UrlPathEncode(DataSet2.Tables(0).Rows(x).Item(3)))

  138                             Else

  139                                 ' URL field is Null, now, have to use DocID value to obtain path

  140                                 DataSet3 = New DataSet

  141                                 DocGUID = DataSet2.Tables(0).Rows(x).Item(5)

  142                                 strDocGUID = DocGUID.ToString

  143                                 SQLQuery = "select DirName, LeafName from AllDocs where id = '" & strDocGUID & "'"

  144                                 DataAdapter = New SqlClient.SqlDataAdapter(SQLQuery, SQLConnection)

  145                                 DataAdapter.Fill(DataSet3)

  146                                 output.RenderBeginTag("a class=ms-navitem href=http://" & strRootURL & "/" & System.Web.HttpUtility.UrlPathEncode(DataSet3.Tables(0).Rows(0).Item(0)) & "/" & System.Web.HttpUtility.UrlPathEncode(DataSet3.Tables(0).Rows(0).Item(1)))

  147                             End If

  148 

  149                             output.Write(DataSet2.Tables(0).Rows(x).Item(4))

  150                             output.RenderEndTag()

  151                             output.RenderEndTag()

  152                             output.RenderEndTag()

  153                             output.RenderEndTag()

  154                             output.RenderEndTag()

  155                             output.RenderEndTag()

  156                         Next

  157                     End If

  158                 Next

  159 

  160                 output.RenderEndTag()

  161                 output.RenderEndTag()

  162                 output.RenderEndTag()

  163             End If

  164 

  165             DataSet = Nothing

  166             SQLConnection.Close()

  167         Catch ex As Exception

  168             strError = ex.Message.ToString

  169             output.Write(strError)

  170         Finally

  171 

  172         End Try

If you see any improvements that I can make, let me know by leaving me a comment. Hope this helps someone.

Versioning

  1. Version 1.1 - (2007 May 2) - Bug fixes which include:
    • Applying Quick Launch logic that is used in the SharePoint WSS 40 Free Application templates.
    • Wrapping data retreived from the database and other sources in System.Web.HttpUtility.UrlPathEncode() to prepare for URL formation and usage.
    • Colorized the comments (I'm looking for a Drupal module to automatically do this for me)
  2. Version 1.0 - (2007 Feb 7) - Original Article on recreating the SharePoint v3 Quick Launch through a Web Part

Project: NCAA Basketball Statistics Scraper & Handicapper

Since my SEO Tool has been successfully collecting data and I haven't decided how to display the information, I decided to start collecting data for another project. I remember reading that there was a discussion over the public domain of sports statistics and I personally believe that the data should be free and available to download. However, since it is not and data distribution sites want big money for such information, I did what any good programmer would do - develop a web scraper to parse available data, restucture it and hopefully release it freely to the public (this last statement is probably a no go, but I'll do the necessary research to figure out the potential copyright issues).

So, one would probably ask, once you have the data what do you plan on doing with it? To be honest, the only real use I see outside of eay-to-use public distribution would be to provide the public a "system" for handicapping future contests. Many sites like covers.com that post trends post statistics on an average basis which really misleads someone looking at the matchups. I believe that stronger trends exist when evaluating other factors not necessarily measured or taken into account as well as looking at standard deviations of data and potentially the median of such data.

I actually set myself a deadline for this one - January 1, 2007 so I would check back around then for the SQL scripts needed and hopefully the web interface that allows people to evaluate certain matchups (although as I write that, I'm thinking that it might just be better to automatically evaluate all the games for a day and then rank them - no need for user intervention). Obviously, I could track the accuracy of my predictions and tweak the formula as I see certain trends to improve the accuracy.

Project: SERP Tracking & SEO Analyzer

Finally, I've had a chance to play around with one of the Google APIs. I decided to take my crack at the Google Web Search API since search is the cornerstone of Google's operations. After reading the documentation briefly (and being surprised that they included .Net sample code), I started brainstorming what tools I could build. Eventually, I decided on a SERP tracker/analyzer.

Now, I have quite a long way to go, but I have successfully called the API, extracted the data from a search results and stored the information in the database. For the time being, I am writing the application in VB.Net and utilizing MSFT's SQL Server 2000; however, I have every intention of porting this to other languages and platforms. Finally, I plan on releasing the source freely since the Google Wed Search API has a limit of only 1,000 queries per day and a maximum of 10 results per query. With those limitations, the only way that the "community" can really benefit from this is to run their own specific relevant term searches.

Hopefully, the feature list will include (but not be limited to):

  • Port application to .Net, PHP, Python, MS SQL, MySQL, flat text file
  • Allow users to dynamically update their API Key
  • Allow users to dynamically change their search terms and search depth (without violating API terms and conditions)
  • Store historical SERP data
  • Web interface to display contextual charts and graphs based on filtered criteria
  • Evaluate high ranking pages and upwards moving ranked pages to determine why they are so effective including comparing page rank, page titles, page summary, keyword density, META tags, keywords in headline tags and more commonly used SEO techniques.
  • Track daily application usage (to prevent API ToS violations)

The picture above shows, in simplistic form, how the SERP data could be stored in the database. Eventually, by normalizing the tables outward, I can do further analysis on the pages as I parse the sites returned as the Googlebot would see them. I'm really excited about the potential for an application like this and the SEO implications. I'm sure many tools like this exist, but I hope to deliver the application and the resulting data in an efficient and unique user experience while also making it incredibly easy for someone to setup my application using their own API key and search terms.

Visual Basic - A Good Beginner Language?

Slashdot has a terrific discussion on the merits of Visual Basic as an introductory programming language. As a programmer who started off with Visual Basic, I would have to agree with the common sentiment at Slashdot that VB fails as a good introductory language. However, VB does have its uses in terms of teaching very basic and simple programming concepts, but at what cost? I know that in my own personal experience, I generated some poor coding habits after developing in VB for long extended periods of time where my coding time with C# was much more productive and "code worthy".

Memory usage and allocation are major issues with today's applications and one really must evolve past Object.Dispose and GC.Collect calls to really understand the subject. The limitations of VB are extensive and, like many other Slashdot posters, would suggest avoiding VB and dealing mainly with C# or C as a first language for newbie programmers.

Syndicate content