h1

VB.NET – Trimming Null Characters

November 2, 2009

A while back, I wrote about reading data from a TCP/IP Stream from a VB.NET application. Since that article, our parameters have changed slightly. Now, we are reading a continuous TCP/IP stream, one that is filled with extra spaces and blank characters. It seemed simple enough to fix. Trim(), right?

Well, to my dismay, I saw that my “trimmed” strings were still filled with spaces. In fact, they were identical to the untrimmed version. What gives?

Untrimmed String
“500 G       ”

Trimmed String
“500 G       ”

It turns out there is a Null Character (Chr(0)) in there at the end.

What I had to do is first replace Chr(0) with an empty string and then I could trim. Reversing the order of operations (trimming first and then replacing the Chr(0)) did not work. Code to reproduce and correct the problem is below:

Dim strTemp as String
strTemp = "Test     " + Chr(0)

strTemp = strTemp.Trim()
'-- Uh oh-- that above call was USELESS strTemp is still "Test     " + Chr(0)

strTemp = strTemp.Replace(Chr(0), "")
'-- Getting closer - strTemp is now "Test     "

strTemp = strTemp.Trim()
'-- And now we are where we want to be-- strTemp is now "Test"
h1

Outgoing Email Server Down? Gmail to the Rescue!!!

November 2, 2009

I work on and maintain a number of web applications, almost all of which send outgoing emails. Yesterday, the outgoing SMTP server of one of sites went down. As the vendor struggled with troubleshooting, we needed to find a means to send emails out ASAP. I scrambled around to try to find an alternate server to no avail and then my co-worker, ZJ, had a brilliant idea. Gmail!

This Lifehacking article describes how to use Gmail as your SMTP server. It was exactly what we needed!:

http://m.lifehacker.com/site?t=s39ZPWUx1Aq3nyo7Rm5cJQ&sid=lifehacker

And in case you need that translated to VB.NET code, below is some sample code. It’s is pretty straightforward, but you do want to make use to use SSL to connect to Gmail.


Dim mMessage As System.Net.Mail.MailMessage
Dim mSMTP As System.Net.Mail.SmtpClient

mSMTP = New System.Net.Mail.SmtpClient()
mSMTP.Host ="smtp.gmail.com"
mSMTP.Port = 25
mSMTP.EnableSsl = True
Dim oAuthInfo = New System.Net.NetworkCredential("yourgmailaccount@gmail.com", "yourpassword")
mSMTP.Credentials = oAuthInfo

mMessage.From = New System.Net.Mail.MailAddress("yourfromaddress")
mMessage.Subject = "Email Subject Line"
mMessage.Body = "Email Body"

mSMTP.Send(mMessage)

In regards to the From Address, if it does not match your Gmail address, you will want to set up an alternate Default Address. The Lifehacker article covers that on Page 4, Update 3 from Reader Derek Bennett.

Thanks to ZJ’s idea, Gmail and the Lifehacking article, we were able to get emails back up and running long before the vendor had their issue fixed!

h1

Visual Studio 2003: Unable to start debugging on the web server.

July 16, 2009

This morning, I had a blast from the past. I had to make a small modification to a web application written in Visual Studio 2003. All seemed well, but when I went to debug my web application, I was presented with an error:

Error while trying to run project: Unable to start debugging on the web server.

NET 2003 Error Error while trying to run project: Unable to start debugging on the web server.

Don’t you just love when all you want to do is make a quick change and you end up troubleshooting your dev environment instead?  : )

Well, this solution turned out to be pretty easy. After years of developing in more contemporary versions of Visual Studio, my Virtual Directory in IIS was set to use ASP.NET 2.0 instead of ASP.NET 1.1.4322.

Steps to resolve it:

  1. Open Internet Information Services Manager (can be access via the Administrative Tools section of the Control Panel or by right clicking on My Computer and selecting Manage)
  2. Expand past Web Sites and right click on the web site or the Virtual Directory you are trying to debug and click on PropertiesNET2003Properties
  3. Click on the ASP.NET tab. Here, mine did not read the expected 1.1.4322:NET2003ASPNETBefore
  4. Change the ASP.NET version to the appropriate value and hit Apply.NET2003ASPNETAfter
h1

SQL Server: Query to Update Column Value Based on the Row Number

July 10, 2009

I have a table in a SQL Server 2005 database that includes a SORT_ORDER column. This column contains a number that the application uses to determine what order items should be displayed in a dropdown list. This evening I wanted to do a mass update of all the items in that table and reset the SORT_ORDER to make all the items alphabetic based on another column– TST_NM.

In Oracle, I would have the handy dandy “rownum” call I could tap into. Luckily, I was able to track down a means to do it in SQL Server 2005. Here’s an update statement using SQL Server’s ROW_NUMBER() function.


UPDATE TST
SET Sort_Order = SubQuery.Sort_Order
FROM
(
SELECT TST_ID, Row_Number() OVER (ORDER BY TST_NM) as SORT_ORDER
FROM TST
) SubQuery
INNER JOIN TST ON
SubQuery.TST_ID = TST.TST_ID

Hat Tip to Jens K. Suessmeyer’s reply in Microsoft’s SQL Server Forums for the SubQuery idea!

P.S. SQL Server 2000 does not appear to like the ROW_NUMBER() function.

h1

VB.NET – Pasting Data from a TCP/IP Stream into a Web Page

July 9, 2009

A few weeks ago, I worked with LaCrosse Scales on integrating a Toledo Scale into a web-based document and process management software called Qualtrax. The goal was to automatically take data from the scale (via a TCP/IP stream) and paste it into a field on a web page.

We accomplished this with a small Windows application written inVB.NET on the client machine. Behind the scenes, it monitors the TCP/IP stream. When it receives new data, it simply copies the data into the clipboard and then does a Ctrl-V (aka Paste). From the user’s perspective, all they have to do is put the item on the scale and click on the Scale’s “Print” button.

Because the application is using the Paste function, the scale data isn’t limited to Qualtrax. It could also be pasted into Excel,  Word, Outlook or any other application you have open.

Here are snippets of the code.

First off – you’ll want to import System.Net.Sockets into your class.


Imports System.Net.Sockets

You’ll create and connect a TCPClient object


Dim client As New TcpClient()
Try
     client.Connect(txtServer.Text, txtPort.Text)
Catch ex As Exception
      'Your error handling here
End Try

Next you’ll monitor the stream. When new data is received, copy it to the clipboard and do a SendKeys of “^v” (Ctrl-V).

Try
     Dim stream As NetworkStream = client.GetStream()
     Dim Buffer(client.ReceiveBufferSize) As Byte

     While (stream.CanRead())
          stream.Read(Buffer, 0, client.ReceiveBufferSize)

          Dim returnData As String = Trim(Encoding.ASCII.GetString(Buffer))

          'Copying to the clipboard:
          Clipboard.SetDataObject(returnData)

          'Doing the Send Keys which will paste the data to the active window and element
          SendKeys.SendWait("^v")

          Application.DoEvents()

     End While
Catch ex As Exception
     'Your error handling here
End Try

As a quick note, when you are debugging and it appears your code is frozen on the stream.Read() call, don’t freak out just yet. It is likely just waiting for data from the TCP/IP stream.  Don’t disappoint it– give it some new data and watch it paste away.

h1

ASP.NET 2.0 – Fun with Crystal Reports

July 7, 2009

Recently I’ve been working on a ASP.NET 2.0/Visual Studio 2005 web application that uses the Crystal Report Viewer to display some Crystal Reports. When I went to deploy on a test server, I ran into issues. Here are the solutions and links to the people that helped me along my way.

Deployment

The first challenge was making sure I had all my necessary components up on the test server. I made this a lot harder than it needed to be– trying a variety of different strategies. The easiest one is the one that works– use the Redistribution Install that comes with Visual Studio 2005. It’s located in:

C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\
BootStrapper\Packages\CrystalReports\CRRedist2005_x86.msi

I simply uploaded the file to my test server, ran it and I was good to go.

Hat Tip
Dick Chiang’s Crystal Reports Merge Module for VS 2005

Database Login Prompts

The next thing I wasn’t thrilled with is how it kept prompting me to enter in the database login in order to run the report. Everytime I went to run a report, I was greeted with a “The report you request requires further information” message along with prompts for Server name, Database name, User name and Password.

SQLPrompt

To make the application portable, I wanted to grab all the credentials from a Connection String I already had recorded in the web.config and use that to automatically log into the database and display the report. For that aspect of it, I used
System.Data.SqlClient.SqlConnectionStringBuilder
to parse out the various properties of my Connection String.

 Dim strConn As SqlConnectionStringBuilder

 '-- Reading a "DB_CONNSTRING" entry in the web.config and using that to create
 '-- the new SqlConnectionStringBuilder class
 strConn = New SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings.Item("DB_CONNSTRING").ToString())

 'SQL Server Name  = strConn.DataSource
 'Database Name = strConn.InitialCatalog
 'Database User Id = strConn.UserID
 'Database Password = strConn.Password</pre>

Sending the logon information to Crystal was a little trickier. There were a lot of articles and blogs on the web that just didn’t pan out. SetDatabaseLogon is a deadend. What I found to work the best was a mixture of many solutions. I loaded a ReportDocument object with my report. I cycled through all the tables in that report and set the login information for each table.

Hat Tips:
Crystal Reports for Visual Studio: Two Useful C# Functions
Tristan Collier’s Comment on HowTo: Read the CrystalReportViewer report connection string from the web.config in Crystal Reports
Tip #17 in 20 Secrets of Crystal Reports

     rpt = New ReportDocument()
     rpt.Load(Server.MapPath("reports/My_Crystal_Report.rpt"))
     tmpConnInfo = New ConnectionInfo()
     tmpConnInfo.ServerName = strConn.DataSource
     tmpConnInfo.DatabaseName = strConn.InitialCatalog
     tmpConnInfo.UserID = strConn.UserID
     tmpConnInfo.Password = strConn.Password

     '-- If it is not enough to update the Report Database logon,
     '-- You need to update the source of all the tables being used
     For Each tmpTable In rpt.Database.Tables
          Dim logonInfo As TableLogOnInfo
          logonInfo = tmpTable.LogOnInfo
          logonInfo.ConnectionInfo = tmpConnInfo

          tmpTable.ApplyLogOnInfo(logonInfo)
          tmpTable.Location = tmpTable.Name
     Next</pre>

Once all my tables were initialized with logon information, I set my CrystalReportViewer control to that ReportDocument object and I was good to go.

      CrystalReportViewer1.ReportSource = rpt

And here is all the code all together:


Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
     Dim strConn As SqlConnectionStringBuilder
     Dim tmpConnInfo As ConnectionInfo
     Dim rpt As ReportDocument
     Dim tmpTable As Table

     strConn = New SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings.Item("DB_CONNSTRING").ToString())
     rpt = New ReportDocument()
     rpt.Load(Server.MapPath("reports/My_Crystal_Report.rpt"))

     tmpConnInfo = New ConnectionInfo()
     tmpConnInfo.ServerName = strConn.DataSource
     tmpConnInfo.DatabaseName = strConn.InitialCatalog
     tmpConnInfo.UserID = strConn.UserID
     tmpConnInfo.Password = strConn.Password

     '-- If it is not enough to update the Report Database logon,
     '-- You need to update the source of all the tables being used
     For Each tmpTable In rpt.Database.Tables
          Dim logonInfo As TableLogOnInfo
          logonInfo = tmpTable.LogOnInfo
          logonInfo.ConnectionInfo = tmpConnInfo

          tmpTable.ApplyLogOnInfo(logonInfo)
          tmpTable.Location = tmpTable.Name
     Next

      CrystalReportViewer1.ReportSource = rpt

 End Sub

Provider Errors
Coding was done, but I did have a little bit of troubleshooting to remain. When I put everything up on the test server, I started to receive another error.

Logon failed.
Details: Error code: 0x
Source: ADODB.Connection
Description: Provider cannot be found. It may not be properly installed.

This turned out to be a really easy fix. I had my reports set up to use the SQL Native Client. All I had to do was change my report’s Data Source to use the SQLOLEDB provider instead. Steps are as follows:

  1. In Visual Studio 2005, open up your Crystal Report is Design mode.
  2. Right on the report and choose Database->Set Database Location
    DatabaseSetDatabaseLocation
  3. The Provider currently reads “SQLNCLI”
    ProviderOriginal
  4. Change the Provider to “SQLOLEDB”
    ProviderChangeEnd

Hat Tip
Straightener on ASP.NET Forums

h1

ASP.NET – Getting a Page’s Name From Master Page

July 7, 2009

Yesterday I wanted to empower a new web application to make sure the current visitor was logged in. If not, I wanted to redirect to the Login page. As luck would have it, I already had my pages set up with a Master Page, so I added a quick check in the Page_Load for the MasterPage. If a UserID Session Variable was not already set, I simply redirected to Login.aspx.


If Session.Item("UserID") Is Nothing Then
     Session.Item("UserID") = -1
End If

If Not IsNumeric(Session.Item("UserID")) Then
     Session.Item("UserID") = -1
End If

If Session.Item("UserID") = -1 Then
     Response.Redirect("Login.aspx")
End If

As I was loading my first page up in the web browser, it dawned on me– I made an infinite loop of redirects. My Login.aspx page was using the same Master Page and would fire the same code. Sure enough, Firefox caught it and reported and error back to me.

The page isn’t redirecting properly
Firefox has detected that the server is redirecting the request for this address in a way that will never complete.

So I made a quick correction. I added in a check with the current page name. If it wasn’t Login.aspx, then we redirect. How did I get the page name?

System.IO.Path.GetFileName(HttpContext.Current.Request.FilePath)
(Hat Tip, bullpit from ASP.NET Forums).

Here’s a snippet of the final code in my MasterPage’s Page_Load:


If Session.Item("UserID") Is Nothing Then
     Session.Item("UserID") = -1
End If

If Not IsNumeric(Session.Item("UserID")) Then
     Session.Item("UserID") = -1
End If

strCurrentPage = System.IO.Path.GetFileName(HttpContext.Current.Request.FilePath)
If strCurrentPage.ToUpper() <> "LOGIN.ASPX" Then
      If Session.Item("UserID") = -1 Then
           Response.Redirect("Login.aspx")
      End If
End If
h1

The Idiosyncracies of Google Chrome – View Source

July 1, 2009

I am not required to make our intranet application Chrome-compliant; however, several other developers prefer to roll in Chrome, and I prefer the browser myself. It is fast and lightweight. I prefer all the development tool add-ons in Firefox when I need to do some deep troubleshooting, like Web Developer and Firebug, but they weigh the browser down on initial load. Chrome, on the other hand, just pops right up and I can jump right into surfing; however, Chrome, I am learning, is a very different animal in some ways for surfing and developing for the Web.

View Source

Google Chrome View Source

Google Chrome “View Source”

When you right-click on a web page and select “View Source” in IE or Firefox, you recieve a snapshot of the HTML script behind the page you are currently viewing. Not so with Chrome, which, it took me some time to figure out, submits an HTTP request to the host for the source code. I’m not sure why this is neccessary, as the source code is already loaded, right there behind the page currently being viewed, but that’s how it works.

I found this comment on a post about Chrome’s seemingly stunted “View Source” functionality:

The way chrome behaves when clicking “View page Source” is strange. Let’s say you issue a POST request to one index.php page, on that page want to see the source code. Chrome starts another request to retrieve the document search using GET; with absolutely no regards to the current posted data. Basically you simply get another document from the one you want. Weird to say the least!

Weird to say the least, outright FAIL from a web development standpoint. How am I to see how my dynamically-built web page is writing out source script, if I can’t see what the source looks like built with the submitted POST variables? I have JavaScript compatibility issues in my site that are specific to Chrome, and it’d be nice to see that chrome is getting the HTML I think I’m writing without having to view source in FF or IE.

Well, it turns out that Chrome goes one better than “View Source,” incorporating functionality I could previously only get in FF with add-ons.

Inspect Element

Right-clicking within a web page in Chrome and selecting “Inspect Element” will open the Inspector console, a traversable tree representation of the document object model focused on the selected node:

Google Chrome Inspector

Google Chrome Inspector

Why put this functionality behind “Inspect Element” and not “View Source?” Because “View Source” presents the source code that Google Chrome recieved from the host, while “Inspect Element” shows what the DOM looks like at the present moment. This is an important distinction, because Chrome, like most browsers, attempts to correct malformed XHTML. So when you view source, you are seeing the HTML as it was sent, when you Inspect Element, you are seeing the HTML as Google Chrome has reformated it.

For instance, the following XHTML in “View Source:”


<table>
<tr>
Hello
<td>World!</td>
</tr>
</table>

Is rendered in “Inspector” as:


Hello
<table>
<tr>
<td>World!</td>
</tr>
</table>

This is a huge feature for a baseline web browser. It appears to be just as sophisticated as Web Developer for Firefox too, highlighting objects on the page as I hover over their source code in the Inspector, and providing the ability to expand and collapse node trees as I need to navigate the DOM. It also has an error log which handles malformed XHTML as well as JavaScript errors. It’s especially useful for troubleshooting HTML dynamically modified with JavaScript, since you can modify an element with JavaScript, such as by cloning it or with an AJAX response, and then see the resulting HTML.

Error Console

Error Console

What a comprehensive solution, and the browser still opens with a snap of my fingers! Suddenly I am in love with Google Chrome again!


Additional Notes:

  • I still have no idea why Chrome has to make an HTTP request to get the XHTML source. It could be argued that this functionality is a “feature,” protecting the page source from prying eyes that haven’t submitted the proper POST variables to access it. Of course, those variables are available on the preceeding web page, and may be submitted through other means… and the source is available with Inspect Element–Oh, I dunno. I’ll stop thinking out loud now.
  • One additional quibble with Chrome’s “View Source:” Firefox presents the HTML in a nifty syntax-highlighted format for easy reading in its custom viewer, while IE opens the file in whatever prefered text-editor you have installed. I like IE’s strategy, since I can open the HTML in UltraEdit and go to town with that software’s arsenal of editing features, but Firefox’s built-in text-editor has lots of sweet features too, like reloading, syntax highlighting, and being able to save the source off to your local drive. Chrome’s “View Source” is view-only, so I have to CTRL-A, CTRL-C, and CTRL-P it into UltraEdit.
  • Okay, I’m done whining now.
  • h1

    TallPDF: Table Width

    June 25, 2009

    Are you working with TallComponent’s TallPDF.NET and having trouble getting your table sizes to come out as expected? You can stop rehashing your Table.PreferredWidth and Table.ForceWidth properties. Instead, take a look at your Section setup. Make sure you explicitly setting up all our of your Margins.

    I had a PDF where I set the Left Margin, but missed the Right one. It was my margins, not my table settings, that was causing the mysterious shrinking of my table.

    Before

    sec = doc.Sections.Add()
    sec.Margin.Left = 36
    

    After

    sec = doc.Sections.Add()
    sec.Margin.Left = 36
    sec.Margin.Right= 36
    

    TallComponentsBeforeAfterCropped
    Before and After

    h1

    JavaScript: Getting Page’s QueryString

    June 25, 2009

    Quick and easy. I needed to grab all of the parameters to my page, so I could pass them along to the next page. The code to get a page’s QueryString via JavaScript:

    strURL = document.location.href;
    pos = strURL.indexOf('?');
    
    strQueryString = strURL.substring(pos + 1);