Web Code Blog

A web repository of coding tips and knowledge base articles

Archive for the ‘.NET’ Category

Quickly check if network file or path exists in VB.NET

Posted by Stefan Zvonar on May 31, 2011

This little article explains a way to check if a file or path exists in code, without having to wait a long time for the result if the network is down or the path does not exist.

For example, in my particular case, I wanted a way to check for connectivity to the network before accessing the server file system. Scaling the internet I found some good C# examples (like this one: http://stackoverflow.com/questions/1232953/speed-up-file-exists-for-non-existing-network-shares)

However, the application I was working on was developed in VB.Net and the threading code is quite different between the languages.

The first problem I encountered was trying to pass a variable to the threading function. After some playing around, I was able to produce the following in VB.Net (based on the example in the link above) and using Visual Studio 2008.

   Public Function PathExists(ByVal path As String, ByVal timeout As Integer) As Boolean
        Dim exists As Boolean = True
        Dim t As New Thread(DirectCast(Function() CheckPathFunction(path), ThreadStart))
        t.Start()
        Dim completed As Boolean = t.Join(timeout)
        If Not completed Then
            exists = False
            t.Abort()
        End If
        Return exists
    End Function

    Public Function CheckPathFunction(ByVal path As String) As Boolean
        Return System.IO.File.Exists(path)
    End Function 

Note: To use this method, you would call the function like done below, passing in an integer representing milliseconds before it stops trying to reach the path – in this case I have set it to 3 seconds.

If PathExists("\\BLAH\PATH\", 3000) Then 
...
End If

Hope this helps,

Stefan.

For more Web Code, ASP.NET, SQL Server and other development tips, please check back here at webcodeblog.com often.

Posted in .NET | 2 Comments »

ASP.NET website not working with DNS Alias

Posted by Stefan Zvonar on April 5, 2011

This is a curious bit of information I have stumbled upon.

An ASP.NET Web Site will not persist session variables between requests when the host name has an underscore (“_”) in it. This is only apparent when using Internet Explorer.

Turns out that underscores are against the standard of naming servers. The particular server I was using decided they wanted to use a DNS Alias for all requests (in case of server name changes in the future). However, the alias itself had an underscore in it, which stopped page requests from working properly in the ASP.NET web site.

Here is a little summary from Microsoft:

SYMPTOMS

After you install security patch MS01-055 for Microsoft Internet Explorer 5.5 or 6.0, you may encounter the following problems:

* Session variables are lost.
* Session state is not maintained between requests.
* Cookies are not set on the client system.

Note These problems can also occur after you install a more recent patch that includes the fix that is provided in security patch MS01-055.

CAUSE
Security patch MS01-055 prevents servers with improper name syntax from setting…
Security patch MS01-055 prevents servers with improper name syntax from setting cookies names. Domains that use cookies must use only alphanumeric characters (“-” or “.”) in the domain name and the server name. Internet Explorer blocks cookies from a server if the server name contains other characters, such as an underscore character (“_”).

Because ASP session state and session variables rely on cookies to function, ASP cannot maintain session state between requests if cookies cannot be set on the client.

This issue can also be caused by an incorrect name syntax in a host header.

RESOLUTION
To work around this problem, use one of the following methods: Rename the domai…
To work around this problem, use one of the following methods:

* Rename the domain name and the server name, and use only alphanumeric characters.
* Browse to the server by using the Internet Protocol (IP) address rather than the domain/server name.

Note You may need to change the Microsoft Internet Information Server (IIS) configuration after you rename a server.

Click here to read the full Microsoft Support Article.

Hope this helps,

Stefan.

For more Web Code, ASP.NET, SQL Server and other development tips, please check back here at webcodeblog.com often.

Posted in .NET, ASP.NET, IIS | Leave a Comment »

Click Once Application Error – The signer’s certificate is not valid for signing

Posted by Stefan Zvonar on November 17, 2010

Problem:

When trying to publish a Click Once application, you recieve the following error:
“The signer’s certificate is not valid for signing.”
Reason:
This is most likely due to the fact that the certificate used to publish the application originally has expired.  Most certificates have a lifespan of about a year, so it needs updating now and then, especially when publishing new versions of the application.

Solution:
To get around this problem, you need to create a new certificate.
Open your project in Visual Studio and go to the Project menu -> Project Properties.  Click on the Signing tab and click on the “Create Test Certificate” button (as shown in the image below).

Create Test Certificate

Create Test Certificate

I left the password blank, but if you do use a password, be sure to remember it a year later, or whenever you need to regenerate another certificate :)
This will place a ????.pfx file in your project.  This file contains the private and public key informaiton.  I simply removed the old file (backed it up first) and renamed my new generated file to the old file name.
You should now be able to publish your Click Once application.

Hope this helps,

Stefan.

For more Web Code, ASP.NET, SQL Server and other development tips, please check back here at webcodeblog.com often.

Posted in .NET, Visual Studio | Leave a Comment »

Save and retrieve images / documents into SQL Server using ASP.NET

Posted by Stefan Zvonar on August 22, 2010

In this article I will explain how to save and retrieve VARBINARY(MAX) data into SQL Server using ASP.NET.  You may opt to do this to store images or documents into the database.

So, let us start at the database level.  Below is a simplistic table definition for storing our files into a table:

CREATE TABLE [dbo].[tb_File](
    [FileID] [int] IDENTITY(1,1) NOT NULL,
    [FileName] [varchar](255) NOT NULL,
    [FileData] [varbinary](max) NOT NULL,
    [FileContentType] [varchar](255) NOT NULL,
 CONSTRAINT [PK_TB_FILE] PRIMARY KEY CLUSTERED
(
    [FileID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

And here are two simple stored procedures to save and retrieve the file data:

CREATE PROCEDURE dbo.usp_File_Get
(
     @FileID int
)

AS

BEGIN

    SET NOCOUNT ON

    SELECT FileID
      ,[FileName]
      ,FileData
      ,FileContentType
    FROM tb_File
    WHERE FileID = @FileID
   SET NOCOUNT OFF

END
GO

And

CREATE PROCEDURE dbo.usp_File_Insert
( 
     @FileName varchar(255),
     @FileData varbinary(max),
     @FileContentType varchar(255)
)

AS

BEGIN

    SET NOCOUNT ON
  
    INSERT INTO tb_File ([FileName], FileData, FileContentType)
    VALUES (@FileName, @FileData, @FileContentType) 
    SET NOCOUNT OFF

END
GO

Now that we have the database objects in place, lets create a basic maintenance web page to be able to upload a file and save it to the database:

Markup:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Upload file to database</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                File Name:
            </div>
            <div>
                <asp:TextBox runat="server" ID="txtFileName"></asp:TextBox>
            </div>
            <br />
            <div>
                File:
            </div>
            <div>
                <asp:fileupload runat="server" id="uplFile" />
            </div>
            <br />
            <div>
                <asp:button ID="btnSave" runat="server" text="Save" OnClick="btnSave_Click" />
            </div>
        </form>
    </body>
</html>

Code-Behind:

 Partial Class _Default
    Inherits System.Web.UI.Page

    Private m_strFileName, m_strFileContentType As String
    Private m_intFileLen As Integer
    Private m_byteFileData As Byte()

    Protected Sub btnSave_Click(ByVal sender As Object, ByVal e As EventArgs)

        GetFileData()
        SaveData()

    End Sub

    Private Sub GetFileData()

        Dim myFile As HttpPostedFile = uplFile.PostedFile
        m_strFileName = System.IO.Path.GetFileName(uplFile.FileName)
        m_strFileContentType = myFile.ContentType
        m_intFileLen = myFile.ContentLength
        m_byteFileData = Nothing

        ' make sure the size of the file is > 0
        If m_intFileLen > 0 Then
            ' Allocate a buffer for reading of the file
            m_byteFileData = New Byte(m_intFileLen - 1) {}

            ' Read uploaded file from the Stream
            myFile.InputStream.Read(m_byteFileData, 0, m_intFileLen)

        End If

    End Sub

    Private Sub SaveData()

        Dim conSQL = New SqlClient.SqlConnection
        conSQL.ConnectionString = "Your database connection string"
        conSQL.Open()

        Dim comSQL As New SqlClient.SqlCommand()

        With comSQL

            .CommandText = "dbo.usp_File_Insert"
            .Connection = conSQL
            .CommandType = CommandType.StoredProcedure
            .Parameters.AddWithValue("@FileName", m_strFileName)

            .Parameters.Add("@DocData", SqlDbType.VarBinary, -1)   ' Need to set size to -1 since it is varbinary(max)
            If m_byteFileData Is Nothing Then
                .Parameters("@DocData").Value = System.DBNull.Value
            Else
                .Parameters("@DocData").Value = m_byteFileData
            End If

            .Parameters.AddWithValue("@DocContentType", m_strFileContentType)
            .ExecuteNonQuery()
        End With

        conSQL.Close()
        conSQL.Dispose()

    End Sub

End Class

Now lets look at how we can view the stored binary data through ASP.NET. Below we have a simple handler that is passed a File ID as a Querystring. It will look up the ID in the database and then write the object out as a byte stream.

<%@ WebHandler Language="VB" Class="FileHandler" %>
Imports System
Imports System.Web
Imports System.Web.Services

Public Class FileHandler
    Implements System.Web.IHttpHandler

    Private m_strFileContentType As String = String.Empty
    Private m_objFileData As Object
    Private m_intFileID As Integer

    ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property


    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest

        GetData(context)
        ShowFile(context)

    End Sub

    Private Sub GetData(ByVal context As HttpContext)

        If context.Request.QueryString("ID") IsNot Nothing AndAlso context.Request.QueryString("ID").Trim() <> String.Empty AndAlso IsNumeric(context.Request.QueryString("ID").Trim()) Then
            m_intFileID = CInt(context.Request.QueryString("ID").Trim())

            Dim conSQL = New SqlClient.SqlConnection
            conSQL.ConnectionString = "Your database connection string"
            conSQL.Open()

            Dim comSQL As New SqlCommand("dbo.usp_File_Get")
            comSQL.Connection = conSQL
            comSQL.Parameters.AddWithValue("@FileID", m_intFileID)
            comSQL.CommandType = CommandType.StoredProcedure

            'read record from database
            Dim drdDrillInstructions As SqlDataReader
            drdDrillInstructions = comSQL.ExecuteReader()
            Try
                If (drdDrillInstructions.HasRows) Then
                    While drdDrillInstructions.Read()
                        m_strFileContentType = drdDrillInstructions.Item("FileContentType").ToString()
                        m_objFileData = drdDrillInstructions.Item("FileData")
                    End While
                End If
            Catch ex As Exception
                ' Publish error here
            Finally
                If Not drdDrillInstructions.IsClosed Then
                    drdDrillInstructions.Close()
                End If
                conSQL.Close()
                conSQL.Dispose()
            End Try
        End If

    End Sub

    Private Sub ShowFile(ByVal context As HttpContext)

        ' Clear out the existing HTTP header information
        context.Response.Expires = 0
        context.Response.Buffer = True
        context.Response.Clear()

        If m_objFileData IsNot Nothing AndAlso (Not DBNull.Value.Equals(m_objFileData)) Then
            context.Response.ContentType = m_strFileContentType
            context.Response.BinaryWrite(DirectCast(m_objFileData, Byte()))
        Else
            context.Response.Write("<html><body bgcolor='#D6EBFF'><p align='center'><br /><br /><br /><br /><br />")
            context.Response.Write("<font class='text'>(No file available)</font>")
            context.Response.Write("</p></body></html>")
        End If

    End Sub

End Class

Hope this helps,

Stefan.

For more Web Code, ASP.NET, SQL Server and other development tips, please check back here at webcodeblog.com often.

Posted in .NET, ASP.NET, SQL Server | 3 Comments »

Removing objects while iterating through collections

Posted by Stefan Zvonar on June 30, 2010

Here is a quick little tip ….

If you need to iterate through a collection of some sort and delete items as you go, you will not be able to remove the object while moving forward through the collection.  The answer?  Go backwards!  Here is an example:

        For Each table As DataTable In myDataSet.Tables()
            ' Loop backwards so that we can remove the column without interfering with our iteration
            For i As Integer = table.Columns.Count - 1 To 0 Step -1
                ' Enter your own checks here
                table.Columns.RemoveAt(i)
            Next
        Next

Hope this helps,

Stefan.

For more Web Code, ASP.NET, SQL Server and other development tips, please check back here at webcodeblog.com often.

Posted in .NET | Leave a Comment »

Create a simple jQuery overlay popup after performing a server-side postback

Posted by Stefan Zvonar on May 21, 2010

In this example, I am going to show how to create a simple jQuery popup overlay after performing a server-side postback.  This will be done just by clicking a simple button.

Before clicking button:

Before clicking button

Before clicking button

After clicking button and performing some server-side processing:

After clicking button

After clicking button

Creating the HTML

Include jQuery libraries:

Link to the standard jQuery library and the jQuery Tools library.  In this example, I link to jQuery in the header of my HTML.

Overlay popup:

You will want to style your popup overlay, so in this example I am just going to create a style class in the header of my HTML called “overlay”.  This style is used to dress the popup div called “divPopUp”.  Initially this div is not displayed.

Button control:

Create a button control (or other control) that you want to use to contact the server.  This is where the server-side processing will occur and eventually create the popup overlay.

Here is my complete HTML:

 <html>
    <head>
        <title></title>
        <script src="scripts/jquery-1.4.2.min.js" type="text/javascript"></script>
        <script src="scripts/jquery.tools.min.js" type="text/javascript"></script>

        <style type="text/css">
            .overlay {
                background-color:#fff;
                display:none;
                width:350px;
                padding:15px;
                text-align:left;
                border:3px solid #333;

                -moz-border-radius:6px;
                -webkit-border-radius:6px;
                -moz-box-shadow: 0 0 50px #ccc;
                -webkit-box-shadow: 0 0 50px #ccc;
            }
        </style>
    </head>

    <body>

        <form id="form1" runat="server">
            <div>
                <asp:Button ID="btnDoStuff" runat="server" Text="Do Stuff" />
            </div>
            <div class="overlay" id="divPopUp" style="width:450px">
                    <h3>Hello</h3>
                    <p>
                         Do you like my pop up?
                    </p>
                    <button>Close</button>
            </div>
        </form>

    </body>

</html>

Implementing the server-side code

On the page code-behind, implement the event handler for the button click. Here write whatever it is that is necessary on the server post-back and then register some new jQuery to be run once the page document is loaded and ready to run, as shown below:

    Protected Sub btnDoStuff_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDoStuff.Click
        ' Do whatever other server-side code you want done here
        ' Now show the popup overlay
        ShowPopUpOverlay()
    End Sub

    Private Sub ShowPopUpOverlay()

        'Create the client script
        Dim sbOverlay As New StringBuilder
        sbOverlay.Append("$(document).ready(function()" & vbCrLf)
        sbOverlay.Append("{" & vbCrLf)
        sbOverlay.Append("$(""#divPopUp"").overlay({" & vbCrLf)
        sbOverlay.Append("// custom top position" & vbCrLf)
        sbOverlay.Append("top: 272," & vbCrLf)
        sbOverlay.Append("expose: {" & vbCrLf)
        sbOverlay.Append("Color: '#999'," & vbCrLf)
        sbOverlay.Append("loadSpeed: 200," & vbCrLf)
        sbOverlay.Append("// highly transparent" & vbCrLf)
        sbOverlay.Append("opacity: 0.5" & vbCrLf)
        sbOverlay.Append("}," & vbCrLf)
        sbOverlay.Append("closeOnClick: false," & vbCrLf)
        sbOverlay.Append("api: true" & vbCrLf)
        sbOverlay.Append("// load it immediately after the construction" & vbCrLf)
        sbOverlay.Append("}).load();" & vbCrLf)
        sbOverlay.Append("});" & vbCrLf)
        ClientScript.RegisterClientScriptBlock(GetType(Page), Guid.NewGuid().ToString(), sbOverlay.ToString(), True)

    End Sub

Hope this helps,

Stefan.

For more Web Code, ASP.NET, SQL Server and other development tips, please check back here at webcodeblog.com often.

Posted in .NET, ASP.NET, JavaScript / jQuery | 2 Comments »

Obtain Latitude and Longitude co-ordinates for an Address using ASP.NET and the Google Maps API

Posted by Stefan Zvonar on April 24, 2010

In this article, I will try and explain how to obtain the latitude and longitude co-ordinates for an address using the Google Maps API.  The reason you will need the latitudes and longitudes for addresses is mainly so that you can store this information along with your address information in the event that you may want to show these addresses on a map (on your website for example).

So, first things first, if you have not already applied for a Google Maps API Key, make sure you do so by following this link (http://code.google.com/apis/maps/signup.html).

Now, create a simple ASP.NET web form.  On this web form’s aspx page, you will want to make a reference to Google Maps.  So place code like the below onto your page:

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=YabbaDabbaDoo" type="text/javascript"></script>

Note: You will want to replace the “YabbaDabbaDoo” with your own Google Maps API Key.

In the body of your web page, lets place some textboxes on the form so that we can enter the address details that we want to find the co-ordinates for (and a button to perform the co-ordinates calculation):


<div align="left"><b>Address Line 1:</b></div>
<div><asp:TextBox id="txtAddress1" TextMode="MultiLine" Rows="2" runat="server" MaxLength="50" ></asp:TextBox></div>
<div align="left"><b>Address Line 2:</b></div>
<div><asp:TextBox id="txtAddress2" TextMode="MultiLine" Rows="2" runat="server" MaxLength="50" ></asp:TextBox></div>
<div align="left"><b>Town:</b></div>
<div><asp:TextBox id="txtTown" runat="server" MaxLength="50"></asp:TextBox></div>
<div align="left"><b>Postcode:</b></div>
<div><asp:TextBox id="txtPostcode" runat="server" MaxLength="10"></asp:TextBox></div>
<div align="left"><b>Country:</b></div>
<div><asp:TextBox id="txtCountry" runat="server" MaxLength="50"></asp:TextBox></div> 

<div align="left"></div>
<div><input id="btnCalculateCoordinates" type="button" value="Calculate Coordinates"
            onclick="calculateCoordinates();" /></div>
<div align="left"><b>Latitude:</b></div>
<div><asp:TextBox id="txtLatitude" runat="server" Width="100px"></asp:TextBox></div>
<div align="left"><b>Longitude:</b></div>
<div><asp:TextBox id="txtLongitude" runat="server" Width="100px"></asp:TextBox></div> 

    

Now all that is left to do is to create the javascript function that will perform the calculation. So here it is:


<script type="text/javascript">

    function calculateCoordinates() {

        var txtAddress1 = document.getElementById('<%= txtAddress1.ClientID%>');
        var txtAddress2 = document.getElementById('<%= txtAddress2.ClientID%>');
        var txtTown = document.getElementById('<%= txtTown.ClientID%>');
        var txtPostcode = document.getElementById('<%= txtPostcode.ClientID%>');
        var txtCountry = document.getElementById('<%= txtCountry.ClientID%>');
        var txtLatitude = document.getElementById('<%= txtLatitude.ClientID%>');
        var txtLongitude = document.getElementById('<%= txtLongitude.ClientID%>');

        var address = txtAddress1.value + ', ';
        address += txtAddress2.value + ', ';
        address += txtTown.value + ', ';
        address += txtPostcode.value + ', ';
        address += txtCountry.value;

        var geocoder;
        geocoder = new GClientGeocoder();
        geocoder.getLatLng(address, function(latlng) {
            if (!latlng) {
                alert(address + ' not found');
            } else {
                txtLatitude.value = latlng.lat();
                txtLongitude.value = latlng.lng();
            }
        });

    }

</script> 

Hope this helps,

Stefan.

For more Web Code, ASP.NET, SQL Server and other development tips, please check back here at webcodeblog.com often.

Posted in .NET, ASP.NET, Google Maps API, JavaScript / jQuery | 8 Comments »

Setting up Google Maps for ASP.NET and SQL Server

Posted by Stefan Zvonar on April 22, 2010

In this article I will describe how you can create a simple location search feature with Google Maps using ASP.NET and SQL Server.  The basis of this article comes from the Google Maps API Documentation (http://code.google.com/apis/maps/articles/phpsqlsearch.html)

The first thing you will want to do is sign up and get a Google Maps API Key.  You will need one for the domain name of where you will be hosting the map.  You can get your API Key from here (http://code.google.com/apis/maps/signup.html).  Hold onto this key, you will need it later.

The end result will look something like this:

Google Map Example

Google Map Example

First, we need to set up the database.  You will want to store all the locations in a database table.  So lets create this table in SQL Server by using code like the below:

CREATE TABLE [dbo].[tblLocation](
    [LocationID] [int] IDENTITY(1,1) NOT NULL,
    [LocationDescription] [nvarchar](100) NOT NULL,
    [Address1] [nvarchar](50) NOT NULL,
    [Address2] [nvarchar](50) NULL,
    [Town] [nvarchar](50) NOT NULL,
    [County] [nvarchar](50) NULL,
    [Postcode] [nvarchar](10) NOT NULL,
    [Country] [nvarchar](50) NOT NULL,
    [Latitude] [decimal](10, 7) NOT NULL CONSTRAINT [DF_tblLocation_Latitude]  DEFAULT ((0)),
    [Longitude] [decimal](10, 7) NOT NULL CONSTRAINT [DF_tblLocation_Longitude]  DEFAULT ((0))
 CONSTRAINT [PK_tblLocation] PRIMARY KEY CLUSTERED
(
    [LocationID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, 
ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]

GO

You can then pre-populate this table with your store locations. Here is an SQL example:

insert into dbo.tblLocation(LocationDescription, Address1, Address2, Town, County, Postcode, Country,
                            Latitude, Longitude)
values('Earls Court', '50 Earls Court Road', 'Earls Court', 'London', NULL, 'W8 6JE', 'United Kingdom',
       51.49635, -0.19664)

insert into dbo.tblLocation(LocationDescription, Address1, Address2, Town, County, Postcode, Country,
                            Latitude, Longitude)
values('Cromwell Place', '50 Cromwell Road', 'Earls Court', 'London', NULL, 'W8 6JE', 'United Kingdom',
       51.49464, -0.19209)

insert into dbo.tblLocation(LocationDescription, Address1, Address2, Town, County, Postcode, Country,
                            Latitude, Longitude)
values('South Kensington Mall', '10 Old Brompton Road', 'South Kensington', 'London', NULL, 'W8 6JE', 'United Kingdom',
       51.49295, -0.17728)

Note, to get the actual latitudes and longitudes for your locations, you can either use your local postal service data or use Google Maps. You can read my post about obtaining latitude and longitude co-ordinates for an address here (http://webcodeblog.com/2010/04/24/obtain-latitude-and-longitude-co-ordinates-for-an-address-using-asp-net-and-the-google-maps-api/)

Now that you have a locations table and some location data, you will want to create a stored procedure to find all the locations based on some parameters. This will use some maths to find the nearest locations based on a passed in co-ordinate (Haversine formula).  Do not worry so much about the maths of it unless you really want to.  We also want the code to return XML as we will eventually be looking at the resultset with JavaScript.

Here is the basic procedure code:

CREATE PROCEDURE [dbo].[proc_Location_List]
    (
        @dmlLat decimal(10, 7),
        @dmlLng decimal(10, 7),
        @intRadius int
    )
    As

SET NOCOUNT ON

DECLARE @intMilesModifier int
SET @intMilesModifier = 3959  -- If using kilometers, use 6371 instead of 3959

-- Select locations that are near the parameters based on distance formula on a sphere
SELECT LocationID, LocationDescription, Address1, Address2, Town, County, Postcode, Latitude, Longitude,
      (@intMilesModifier*acos(cos(radians(@dmlLat))*cos(radians(Latitude))*cos(radians(Longitude)-
       radians(@dmlLng))+sin(radians(@dmlLat))*sin(radians(Latitude)))) AS distance
FROM dbo.tblLocation
WHERE (@intMilesModifier*acos(cos(radians(@dmlLat))*cos(radians(Latitude))*cos(radians(Longitude)-
       radians(@dmlLng))+sin(radians(@dmlLat))*sin(radians(Latitude)))) < @intRadius

-- Return XML for formatting results
FOR XML RAW('marker'),ROOT('markers')

SET NOCOUNT OFF
GO

Executing the above stored procedure will render XML like the below:

<markers>
    <marker LocationID="1" LocationDescription="Earls Court" Address1="50 Earls Court Road" 
            Address2="Earls Court" Town="London" Postcode="W8 6LE" Latitude="51.4963500"
            Longitude="-0.1966400" distance="1.669166379205019e-001" />
    <marker LocationID="2" LocationDescription="Cromwell Place" Address1="50 Cromwell Road"
            Address2="Earls Court" Town="London" Postcode="W8 6LE" Latitude="51.4946400" 
            Longitude="-0.1920900" distance="2.747850170042376e-001" />
    <marker LocationID="3" LocationDescription="South Kensington Mall" Address1="10 Old Brompton Road"
            Address2="South Kensington" Town="London" Postcode="W8 6LE" Latitude="51.4929500"
            Longitude="-0.1772800" distance="9.144638212456977e-001" />
</markers>

That completes the SQL Server side of it. Now it is time to create some basic ASP.NET pages to show the location results.

You will essentially want two pages 1) A Search Request Page and 2) A Search Response Page.

Here is an snippet of code that demonstrates how the Search Request Page could look like (SearchRequest.aspx):

<div style="margin-left:20px;">


    <div style="margin-left: 5px;">
        <span style="font-size: 10px;">Please enter an address, town or post code and click search</span>
        <br />
        Address: <input type="text" id="txtSearchAddress" value="High Street Kensington" />&nbsp;
        Country: <input type="text" id="txtSearchCountry" value="United Kingdom" />&nbsp;
        Distance:
        <select id="ddlRadius">
          <option value="5" selected>5 miles</option>
          <option value="10">10 miles</option>
          <option value="25">25 miles</option>
          <option value="50">50 miles</option>
          <option value="100">100 miles</option>
        </select>&nbsp;
        <input type="button" onclick="searchLocations()" value="Search"/>
    </div>

    <br />

    <div style="clear:both; margin-left: 5px;">
        <div id="sidebar" style="overflow: auto; height: 400px; width:150px; font-size: 11px; color: #000; 
             float:left; margin-left:5px; padding-left:5px;">Search Results:</div>
        <div style="float:left; margin-left: 5px;">
            <div id="GoogleMap_Div_Container">
                <div id="map" style="width:750px;height:400px;"></div>
            </div>
            <!-- Google Map API Key -->
            <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=YabbaDabbaDoo"  
                    type="text/javascript"></script>

        </div>

    </div>

    <br style="clear:both;" />

    

</div>   

Note: In the above, you might want to change the key value of “YabbaDabbaDoo” to your own API Key that you generated when you registered with Google Maps.

On the same page, we will load all the Google map JavaScript that sets up the map and the calls to the Google Maps API. Here is an example of the JavaScript you will need on the page:

<script language="javascript" type="text/javascript">

    // Google Map API Javascript

    var map;
    var geocoder;
    var http_request = false;
    var lat = 0;
    var lng = 0;
    var startingLat = 54.1509;  // view of england
    var startingLng = -4.4855;  // view of england
    var startingZoom = 5;
    var maximumZoom = 15;

    function mapLoad() {
        if (GBrowserIsCompatible()) {
            geocoder = new GClientGeocoder();
            map = new GMap2(document.getElementById('map'));
            map.addControl(new GSmallMapControl());
            map.addControl(new GMapTypeControl());
            map.enableScrollWheelZoom();
            map.setCenter(new GLatLng(startingLat, startingLng), startingZoom);
        }

    }

    function searchLocations() {

        var address = document.getElementById('txtSearchAddress').value;
        var country = document.getElementById('txtSearchCountry').value;
        var searchString = address + ', ' + country;

        geocoder.getLatLng(searchString, function(latlng) {
            if (!latlng) {
                alert(searchString + ' - not found');
            } else {
                searchLocationsNear(latlng);
            }
        });
    }

    function searchLocationsNear(center) {
        var radius = document.getElementById('ddlRadius').value;
        var searchUrl = 'SearchResponse.aspx?lat=' + center.lat() + '&lng=' + center.lng() + '&radius=' + radius;

        GDownloadUrl(searchUrl, function(data) {
            var xml = GXml.parse(data);
            var sidebar = document.getElementById('sidebar');
            sidebar.innerHTML = '';
            map.clearOverlays();

            if (xml.documentElement == null) {
                sidebar.innerHTML = 'No results found.  Please try widening your search area.';
                map.setCenter(new GLatLng(startingLat, startingLng), startingZoom);
                return;
            }

            var markers = xml.documentElement.getElementsByTagName('marker');

            if (markers.length == 0) {
                sidebar.innerHTML = 'No results found.  Please try widening your search area.';
                map.setCenter(new GLatLng(startingLat, startingLng), startingZoom);
                return;
            }

            var bounds = new GLatLngBounds();
            for (var i = 0; i < markers.length; i++) {
                var address1 = markers[i].getAttribute('Address1');
                var address2 = markers[i].getAttribute('Address2');
                var town = markers[i].getAttribute('Town');
                var postcode = markers[i].getAttribute('Postcode');
                var distance = parseFloat(markers[i].getAttribute('distance'));
                var point = new GLatLng(parseFloat(markers[i].getAttribute('Latitude')),
                             parseFloat(markers[i].getAttribute('Longitude')));

                var marker = createMarker(point, address1, address2, town, postcode);

                map.addOverlay(marker);
                var sidebarEntry = createSidebarEntry(marker, address1, address2, town, distance);
                sidebar.appendChild(sidebarEntry);
                bounds.extend(point);
            }

            var pointCenter = bounds.getCenter();
            var iZoomLevel = map.getBoundsZoomLevel(bounds);
            if (iZoomLevel > maximumZoom) { iZoomLevel = maximumZoom; }
            map.setCenter(pointCenter, iZoomLevel);

        });
    }

    function createMarker(point, address1, address2, town, postcode) {
        var marker = new GMarker(point);
        var html;
        if (address2 == null) {
            html = '<br/>' + address1 + '<br/>' + town + '<br/>' + postcode;
        }
        else {
            html = '<br/>' + address1 + ', ' + address2 + '<br/>' + town + '<br/>' + postcode;
        }
        GEvent.addListener(marker, 'click', function() {
            marker.openInfoWindowHtml(html);
        });
        return marker;
    }

    function createSidebarEntry(marker, address1, address2, town, distance) {
        var div = document.createElement('div');
        var address;
        if (address2 == '' || address2 == null) {
            address = address1 + '<br/>' + town;
        }
        else {
            address = address1 + '<br/>' + address2 + '<br/>' + town;
        }
        var html = '<b>' + distance.toFixed(2) + ' miles: </b><br/>' + address;
        div.innerHTML = html;
        div.style.cursor = 'pointer';
        div.style.marginBottom = '5px';
        GEvent.addDomListener(div, 'click', function() {
            GEvent.trigger(marker, 'click');
        });
        GEvent.addDomListener(div, 'mouseover', function() {
            div.style.backgroundColor = '#eee';
        });
        GEvent.addDomListener(div, 'mouseout', function() {
            div.style.backgroundColor = '#fff';
        });
        return div;
    }

</script>

When the page loads for the first time, we want to make sure we load up the map JavaScript variables. So in the code-behind of this SearchRequest.aspx page, we will add something like the below in the page load event handler:

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Page.ClientScript.RegisterStartupScript(Me.GetType(), "mapLoad", 
                                           "<script language='javascript'> mapLoad(); </script>")

    End Sub

Okay, so all that is left is the guts for the page that will return the XML. If you create a new page (e.g. SearchResponse.aspx) in the same directory as the Search Request page, then all it needs to do is call the stored procedure that will return the locations as XML and return an XML response. The aspx will be empty except for the page declaration. The code-behind of this Search Response Page will look like the below:

Imports System.Xml

Partial Class SearchResponse
    Inherits System.Web.UI.Page

    ' Page Load
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim dmlSearchLatitude As Double
        Dim dmlSearchLongitude As Double
        Dim intSearchRadius As Int32

        If Request.QueryString("lat") <> "" Then
            dmlSearchLatitude = CDbl(Request.QueryString("lat"))
        End If
        If Request.QueryString("lng") <> "" Then
            dmlSearchLongitude = CDbl(Request.QueryString("lng"))
        End If
        If Request.QueryString("radius") <> "" Then
            intSearchRadius = CInt(Request.QueryString("radius"))
        End If

        ' Here you make the call to your locations stored procedure
        ' This database call is a little messy but is just to show you the point.
        ' You should really use the MS Application Blocks and/or some other seperate data layer
        Dim connDB = New SqlClient.SqlConnection
        Dim cmd As New SqlClient.SqlCommand
        connDB.ConnectionString = "Your database connection string"
        connDB.Open()
        cmd.Connection = connDB
        cmd.CommandType = CommandType.StoredProcedure
        cmd.CommandTimeout = 20
        cmd.CommandText = "dbo.proc_Location_List"
        cmd.Parameters.AddWithValue("@dmlLat", dmlSearchLatitude)
        cmd.Parameters.AddWithValue("@dmlLng", dmlSearchLongitude)
        cmd.Parameters.AddWithValue("@intRadius", intSearchRadius)

        ' Execute the stored procedure and return the result as plain XML
        Dim rdrXMLLocations As XmlReader = Nothing
        rdrXMLLocations = cmd.ExecuteXmlReader()

        Response.Expires = 0
        Response.ContentType = "text/xml"
        Dim oDocument As New XmlDocument()
        Dim sb As New System.Text.StringBuilder()
        Using rdrXMLLocations
            While Not rdrXMLLocations.EOF
                rdrXMLLocations.MoveToContent()
                sb.Append(rdrXMLLocations.ReadOuterXml())
            End While
            rdrXMLLocations.Close()
        End Using
        oDocument.LoadXml(sb.ToString())
        oDocument.Save(Response.Output)
        Response.OutputStream.Flush()
        Response.OutputStream.Close()

    End Sub

End Class

Hopefully that should be enough to get the Google Maps API in action for you.

Click here to download a zip file of the example code used in this article.

Hope this helps,

Stefan.

For more Web Code, ASP.NET, SQL Server and other development tips, please check back here at webcodeblog.com often.

Posted in .NET, ASP.NET, Google Maps API, JavaScript / jQuery, SQL Server | 14 Comments »

Populating a Textbox with JavaScript and ASP.NET code-behind thinks it is empty?

Posted by Stefan Zvonar on April 14, 2010

So, you have placed a textbox onto your web page and populate the textbox using some JavaScript. However, when you submit the form, ASP.NET seems to think that the textbox is empty?

Well, chances are you have probably tried to disable the textbox – most probably because you are trying to stop the user from entering or changing the text themselves. However, there is a solution to this.

As an example, you may have set the ReadOnly attribute on the textbox like the below:

<asp:TextBox ID="txtSomeTextBox" runat="server" TextMode="MultiLine" ReadOnly="true"></asp:TextBox>

Or you may have set the Enabled property to false like the below:

<asp:TextBox ID="txtSomeTextBox" runat="server" TextMode="MultiLine" Enabled="false"></asp:TextBox>

Continuing with the example, you may have a button on the page that populates the above textbox. Something like the below:

<script language="javascript" type="text/javascript">
    function doSomething() {
        document.getElementById('<%=txtSomeTextBox.ClientID %>').value = "abcdefg";
    }
</script>

<input type="button" value="Do Something" onclick="doSomething();" />

When it comes to reading the textbox from the code-behind, ASP.NET thinks the textbox is empty. That is because you have actually set the server control to be unchangable.

A workaround is to simply to append the readonly attribute from within the code-behind, as shown below:

If Not IsPostBack Then
   txtSomeTextBox.Attributes.Add("readonly", "readonly")
End If

That should have the desired effect of still not letting your users change the textbox text and still allowing ASP.NET to read the populated text.

Hope this helps,

Stefan.

For more Web Code, ASP.NET, SQL Server and other development tips, please check back here at webcodeblog.com often.

Posted in .NET, ASP.NET, JavaScript / jQuery | 1 Comment »

Setting up MS Charts for ASP.NET and Visual Studio 2008

Posted by Stefan Zvonar on April 13, 2010

In this article I will try and describe how to set up your Visual Studio 2008 project so you can display some Microsoft Charts on your ASP.NET pages.  The first thing you will want to do is install MS Charts on your development machine (and of course, it will need to be run on each of your web servers that you plan on having chart pages on).

You can download the MS Charts installation file from the Microsoft site, located here: http://www.microsoft.com/downloads/details.aspx?FamilyId=130F7986-BF49-4FE5-9CA8-910AE6EA442C&displaylang=en

You will also need to install the MS Charts Add-In for Visual Studio 2008 so you can develop your charts from the Microsoft sites, located here:  http://www.microsoft.com/downloads/details.aspx?familyid=1D69CE13-E1E5-4315-825C-F14D33A303E9&displaylang=en

Now, you will want to make sure that your web site has a reference to the newly installed .NET component, so add the following .NET component to your web solution: “System.Web.DataVisualization”.

In order to work properly, you will need to make some Web.Config changes.  Here are the necessary Web.Config changes for your charts to execute.

The following goes in <appSettings> section (usually located beneath the </configSections> section)

<add key="ChartImageHandler" value="storage=file;timeout=20;dir=c:\Temp\;"/>

Important: You will want to change the c:\Temp\ directory. If you are using a web farm, I recommend using a shared folder that all the web servers can read and write to, but you may have to discuss this with your system administrator.

The following goes into the <system.web><pages><controls> section:

<add tagPrefix="asp" namespace="System.Web.UI.DataVisualization.Charting"
assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

The following goes in <system.web><compilation><assemblies> section

<add assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral,
PublicKeyToken=31BF3856AD364E35"/>

The following goes in <system.web><httpHandlers> section

<add path="ChartImg.axd" verb="GET,HEAD,POST" 
type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization,
Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>

The following goes in <system.webServer><handlers> section

<remove name="ChartImageHandler"/>
<add name="ChartImageHandler" preCondition="integratedMode" verb="GET,HEAD,POST" path="ChartImg.axd"
type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization,
Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

That is all the Web.Config changes complete.  Now it is time to place a chart into your web page.

Select the web page that you want to use to display the chart.  You will want to place a chart object onto the page, so enter code similar to that shown below into the aspx page.

<asp:Chart ID="Chart1" runat="server" EnableViewState="true">
    <Series>
        <asp:Series Name="Default" BorderColor="180, 26, 59, 105" Color="220, 65, 140, 240">
        </asp:Series>
    </Series>
    <ChartAreas>
        <asp:ChartArea Name="Default" BackColor="Transparent" BorderColor="Transparent">
        </asp:ChartArea>
    </ChartAreas>
</asp:Chart>

In the code-behind file, you will need to reference the charting namespace.  Also, you will need to set up the chart in the page load.  You may also want to set up a click event also, like shown in the code below:

Imports System.Web.UI.DataVisualization.Charting

Partial Class SomePage
    Inherits System.Web.UI.Page

    Protected _PieExplodedIndex As Integer = 0  ' Default exploded pie slice

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If Not IsPostBack Then
            LoadMSChart()
        End If

    End Sub

    ' Load the chart
    Private Sub LoadMSChart()

        Dim arXValues As ArrayList = New ArrayList
        Dim arYValues As ArrayList = New ArrayList

        ' Build up the x and y values (pull from a database, whatever)
        arXValues.Add("Stefan")
        arXValues.Add("Rodger")
        arXValues.Add("Andersen")
        arYValues.Add(100)
        arYValues.Add(80)
        arXValues.Add(100)

        ' Set chart type
        Chart1.Series("Default").ChartType = SeriesChartType.Pie

        ' Show hand pointer so user knows they can click on the pie chart
        Chart1.Style.Add("Cursor", "Hand")

        ' Databind the x and y values to the chart
        Chart1.Series("Default").Points.DataBindXY(arXValues, arYValues)

        ' Enable 3D Styling
        Chart1.ChartAreas("Default").Area3DStyle.Inclination = 20
        Chart1.ChartAreas("Default").Area3DStyle.Enable3D = True
        Chart1.ChartAreas("Default").Area3DStyle.LightStyle = LightStyle.Realistic
        Chart1.ChartAreas("Default").Area3DStyle.Rotation = 45
        Chart1.ChartAreas("Default").BackGradientStyle = GradientStyle.DiagonalRight

        ' Say that we want the slice index as the postback value when user clicks on the chart
        Chart1.Series(0).PostBackValue = "#INDEX"

        ' Size up the chart
        Chart1.Width = 270
        Chart1.Height = 250

        ' Calculate Chart Size, since exploding pie chart slices can distot the size of the pie chart
        CalculateChartSize()

    End Sub

    ' Clicking on the chart event handler
    Protected Sub Chart1_Click(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ImageMapEventArgs) Handles Chart1.Click

        Dim str As String = e.PostBackValue

        If IsNumeric(str) Then
            _PieExplodedIndex = CInt(str)
        End If

        ' Explode / Insert the desired data point
        If Chart1.Series("Default").Points(_PieExplodedIndex)("Exploded") = "true" Then
            Chart1.Series("Default").Points(_PieExplodedIndex)("Exploded") = "false"
        Else
            Chart1.Series("Default").Points(_PieExplodedIndex)("Exploded") = "true"
        End If

        ' Calculate Chart Size, since exploding pie chart slices can distot the size of the pie chart
        CalculateChartSize()

    End Sub

    ' Calculate chart size depending on exploded slice
    Private Sub CalculateChartSize()
        ' For some reason, when no slices are exploded and in 3-D, the pie chart is huge.  So, make the pie chart smaller when there are no exploded indexes
        Dim blnExploded As Boolean = False

        ' See if there is an exploded slice
        For i As Integer = 0 To Chart1.Series("Default").Points.Count - 1
            If Chart1.Series("Default").Points(i)("Exploded") = "true" Then
                blnExploded = True
            End If
        Next

        If blnExploded Then
            ' Normal Chart Size
            If Chart1.ChartAreas("Default").Area3DStyle.Enable3D Then
                Chart1.ChartAreas("Default").InnerPlotPosition = New ElementPosition(0, 0, 100, 100)
            Else
                Chart1.ChartAreas("Default").InnerPlotPosition = New ElementPosition(9, 9, 82, 82)
            End If
        Else
            ' Smaller Chart Size
            Chart1.ChartAreas("Default").InnerPlotPosition = New ElementPosition(9, 9, 82, 82)
        End If

    End Sub

End Class

Just one more thing – at run time, you may occasionally receive an “image not found” exception.  This usually happens when IIS is restarted, the bin folder contents modified or any other reason for the application to restart.  To stop this error from occurring, add the following property to the code-behind of your global.asax file:

Shared _chartInitialized As Boolean

And your application begin request method should have the following piece of code.  What this essentially does is instantiate the charting object before any charts are trying to render and should stop the above exception from occurring (more information about this exception can be found at http://social.msdn.microsoft.com/Forums/en-US/MSWinWebChart/thread/a5b09b47-23b2-4cb4-bc0a-966e486a65a2

        Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)

            ' Check that MS Charts is initialised
            If Not _chartInitialized Then
                _chartInitialized = True
                Dim s As String = ChartHttpHandler.Settings.FolderName
            End If

        End Sub

And that is pretty much it.  Hope it sets you up and you make some nice charts with this cool little .NET bonus.

Hope this helps,

Stefan.

For more Web Code, ASP.NET, SQL Server and other development tips, please check back here at webcodeblog.com often.

Posted in .NET, ASP.NET, MS Charts | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.