|
 Thursday, March 29, 2007

ASP.NET HOWTO: Enable Default Enter Button in ASP.NET 2.0

In certain forms, such as search forms, users enter a value into the search query box, then press the enter button. If you are develolping in ASP.NET, the page will refresh, but nothing will happen. The buttons click event wont fire... UNLESS, you explicity enable a default enter button on the form.

A problem that existed in ASP.NET 1.x was that you could not specify a default enter button unless you provided some custom code. In ASP.NET 2.0 you can do this very easily, unfortunately its not that widely used, much less known.

HOW TO:

The HtmlForm object has a property DefaultButton. This property gets or sets the control that that causes the post back when the ENTER key is pressed.

Example

<body>
   <form id="form1" runat="server" defaultbutton="processRequestButton">
      <div>
         <asp:TextBox AccessKey="c" runat="server" ID="somevalueTextbox"></asp:TextBox>
         <asp:Button runat="server" ID="processRequestButton" Text="Process" OnClick="processRequestButton_Click" />
      </div>
   </form>
</body>

Result

When the user presses the ENTER key, the form will be posted back and the processRequestButton_Click event will be fired.

Simple!

kick it on DotNetKicks.com
#    Comments [4] |
 Tuesday, March 27, 2007

Overcomplicating simple things - ASP.NET AJAX Confirmation Button Extender

Web 2.0, the big hit. Its everywhere, everyone is doing it. Microsoft has made it very easy for us developers to implment some very cool features of AJAX through the ASP.NET Ajax.NET framework. Simply install, drag and drop and deploy, blammo, you're done.

But there in lies the problem. What about developers who take this for granted? This turns our profession into a melting pot of people who think they can code but actually can't do much of anything other than drag and drop. I'm talking about the developers who implement this type of solution and run with it. They have no concern about how it works, why it works the way it does, it just solves the problem. Little did they know, they went through more work getting this done than is required. Continue on...

Introducing the ASP.NET AJAX Confirmation Button Extender...

This extender enhances usability by giving the user a choice of what to do. For example...

I'm all for ease of use, but sometimes even the smartest people can complicate something VERY SIMPLE. We've all suffered from Analysis Paralysis at one point in our career and well, I think the Confirmation Button Extender is a product of that symptom.

Why would I want to use the AJAX>NET framework to implement a simple confirmation box when I could use the OnClientClick with a fraction of the code?

Here's what I'm saying.

AJAX.NET Implementation

<asp:LinkButton runat="server" id="LinkButton1" Text="test" />

<ajaxToolkit:ConfirmButtonExtender ID="cbe" runat="server"
TargetControlID="LinkButton1"
ConfirmText="Are you sure you want to click this?" />

ASP.NET Implementation with JavaScript:

<asp:LinkButton runat="server" ID="testButton" OnClientClick="return confirm('Are you sure you want to click this?');" Text="test" />

These two methods DO THE EXACT same thing. Yes, the markup output is different, but honeslty, the latter of the two is much easier to implement. To implement this in AJAX.NET you have include the dll and js files, blah blah blah.

The problem I have with the AJAX.NET implementation is that its not helping me gain anything. I have to type more code to get the same thing accomplished. I see this as teaching developers its ok to lean heavily on the design time . This is a problem that we've been solving for years in web dev. How to send a confirmation to a user, and it seems, just now, a lot of people are just figuring it out due to AJAX.NET and they think its "the only way", mainly because ... well ... it worked from a drag/drop perspective. Unfortunately it takes more code than necessary and when the developer finally figures out what it does, they usually say "well why did Microsoft implement it that way? This is soo much eaiser doing by using OnClientClick".

My answer: "So you could get it to work, quickly. If developers cant figure it out on their own, then its time abstract the problem out into another level, and thats exactly what they did. Removed the knowledge of how and why, and replaced it with an easy to implement solution."

We call them R.A.D. Tools and sometimes in this industry its a love/hate relationship with them. :)

 

#    Comments [0] |
 Monday, March 26, 2007

error CS0030: Cannot convert type (Login.master)

I ran into an interesting error today and for a minute I didnt understand why it occurred.

Exception
c:\Windows\Microsoft.NET\Framework64\v2.0.50727\Temporary ASP.NET Files\exampleapp\571e5472\336672e2\App_Web_login.master.cdcab7d2.gh4qw4cs.0.cs(115): error CS0030: Cannot convert type 'ASP.login_master' to 'System.Web.UI.WebControls.Login'
http://localhost/exampleapp/login.aspx?ReturnUrl=/exampleapp/default.aspx
/exampleapp/login.aspx


The site ran fine when running under the local cassini web web server but when we pre-compiled the website through our continuous integration system and then dropped it on our test server, everything went hay-wire. This error started popping up.

After a few moments of reviewing the error I figured it out.

The problem

The master page code behind class was called "Login". ASP.NET 2.0 also has a class by the name of Login. The .NET Framework was trying to convert one type (the master page type) to the actual Login class type.

The Fix

You can fix this one of two ways.

1. Give the full type name in the inherits attribute of the master page.

      e.g.: NameSpace.Type

2. Change the code behind class name from "Login" to something like "LoginMaster".

 

Conclusion

As I found (after the fact of solving this) Rahul Soni to say ... "dont give a class the name of 'Login'".

Please note, I've also see this problem with class names that are of the following:

  • Error
  • View
  • Wizard

I'm sure there are more, but these are the ones I've see cause this problem before.

 

 

#    Comments [1] |

IIS 7 - This configuration section cannot be used at this path.

If you're new to IIS 7 (you probably are) you might receive this nice little gem when you first start working with it:

HTTP Error 500.19 - Internal Server Error
Description: The requested page cannot be accessed because the related configuration data for the page is invalid.
Error Code: 0x80070021
Notification: BeginRequest
Module: IIS Web Core
Requested URL: http://localhost:80/ExampleApplication/
Physical Path: C:\inetpub\wwwroot\ExampleApplication\
Logon User: Not yet determined
Logon Method: Not yet determined
Handler: Not yet determined
Config Error: This configuration section cannot be used at this path. This happens when the section is locked at a parent level. Locking is either by default (overrideModeDefault="Deny"), or set explicitly by a location tag with overrideMode="Deny" or the legacy allowOverride="false".
FONT color=#a52a2a>
Config File: \\?\C:\inetpub\wwwroot\ExampleApplication\web.config
Config Source:
  184: 		</modules>
  185: 		<handlers>
  186: 			<remove name="WebServiceHandlerFactory-Integrated"/>

IIS 7 implements "Configuration Locking". This is to help with IIS administration. The IIS Administrator can lock down Configuration Sections, Section Elements and Attributes at the IIS level. This allows the administrator to have a more granular level of control on the system. Read this link to see more about it.

Important Note:  In order make these changes, you must be an administrator on the machine where the config file resides. If its on your local machine, you must be an administrator on your machine. 

Since I'm on my own development machine, and since this is a development machine, I have decided to change the global setting (the config section itselft). To fix this error I had to go to the applicaitonHost.config file and set the overrideModeDefault to "Allow".

Here's how:

Open the applicationHost.config file, located here: %windir%\system32\inetsrv\config\applicationHost.config

In my instance, I need to edit the "handlers" section.

Change this line:

<section name="handlers" overrideModeDefault="Deny" />

To:

<section name="handlers" overrideModeDefault="Allow" />

Thats it. :)


You might receive more errors after you enable this, such as the same error for modules, but just follow the same steps above, and you should be good.

Note: You can accomplish this same thing through the command line by using the appcmd.exe application (%windir%\system32\inetsrv\appcmd.exe). Like this:

%windir%\system32\inetsrv\appcmd unlock config -section:system.webServer/handlers

One more note...

This is not something you'd want to do on a production server unless you're sure you want to enable all appliations to override the section contents. Be sure to read up on some of the docs (explanation of the configuration system) before you make this change on production.

#    Comments [4] |
 Thursday, March 22, 2007

Using Excel to help with Data formatting (SQL Scripts)

(Download Excel Spreadsheet example at the bottom.)

Sometimes when developing I need to work with data. Sometimes this data is from external sources such as other partners in the business. Unfortunately when I get this data does not follow a consistent format therefore I'm left with formatting it for entry into a data store, usually a SQL Server.

In my last post about how to create store locator, I had this same problem. I had to import a list of company addresses for that tutorial. The only place I knew where to get a good list of locations for a store locator would be off of Starbucks Store Locator site. Through the trusty copy/paste method, I was able to grab about 200 store results in a matter of minutes from the website.

Now back to the original problem, the data format. The data looked like this after is was copied...

1. 1385 Metropolitan Ave (UCO)
1385 Metropolitan Avenue
Bronx NY, 10462
United States

I needed it to look like this (for ease of use, plus its easier to debug):

1385 Metropolitan Ave (UCO)
1385 Metropolitan Avenue
Bronx
NY
10462
 
Which will finally transform into this:

INSERT INTO dbo.Locations(LocationName, Address, City, State, Zip) VALUES ('1385 Metropolitan Ave (UCO)', '1385 Metropolitan Avenue', 'Bronx', 'NY', '10462')

Hmmm... problem. Now I could take my time, write an SQL insert script for each and every one of these, but that would take forever.

Instead we can use Excel to do this for us.

First off, all credit for this sweet little trick goes to Chris Lawson (a developer I worked with during my time at Todd McFarlane Producitons, SPAWN.COM). He's the one who showed it to me, I'm just showing it to you. :)

To get the data formatted into SQL insert scripts we need to use a few functions from Excel. We'll mainly use LEFT, MID, RIGHT, TRIM and SEARCH. Using those 4 methods you can pretty much get anything you want out of the string, and thats what I've done.

Note: It might be very helpful if you downloaded my sample at the bottom of this post and read this while looking at the sample, just so you can see how it was done.

Step 1: Separate the Data

We're going to want to take our data from this format:

1. 1385 Metropolitan Ave (UCO)
1385 Metropolitan Avenue
Bronx NY, 10462

and organize it to:
 
1385 Metropolitan Ave (UCO)
1385 Metropolitan Avenue
Bronx
NY
10462

Which will eventually get transformed into SQL, like this ...

INSERT INTO dbo.Locations(LocationName, Address, City, State, Zip) VALUES ('92nd & 3rd', '1642 Third Avenue', 'New York', 'NY', '101283618')


a) Get the Title to look like: 1385 Metropolitan Ave (UCO)

Tasks:
 - Get rid of the "1. " 

This will return the text in A1 without "1. " in it.


This takes the contents in cell A1 (the text with the 1. 1385 Metro...) and gets rid of the 1. through some simple text manipulation. The SEARCH method takes a parameter to search for. Utilizing the single character wildcard "?" I'm able to find where the numbering 'ends' and then get the text after that utilizing the LEN and RIGHT functions.

I'm going to use the same method for each line...
 

Address


 

City


 

State


Zip


Step 2. - Creating the SQL

Now that we have all the fields separated, we can easily create a SQL Script off of this.
Simply concatinate them together.

(click for larger view)


Now that we have all of this done, we can copy, and paste the this code (or click and drag the bottom right corner) throughout the sheet.
This will create the fields and SQL for us.

Then, two lines down...

Which gives us...


Now, select the entire "C" COLUMN and copy it ...

 

Now move that to any column down the line from column "C", lets say, "E". Right click and click "Paste Special"


 

Then click "Values"

 

Step 3 - Extracting the SQL

Now all the actual text values will be placed into the columns. You can now select Column "E" and copy all of those values.

The reason we have to paste special is because otherwise we'd be copying the column caluculations, instead of a pretty SQL script, we'd get a row with no data, such as:

INSERT INTO dbo.Locations(LocationName, Address, City, State, Zip) VALUES ('', '', '', '', '')

By pasting special, we're telling Excel we want the VALUES of the cells, not the actual calculations.

Now that you've "pasted as special" with values, you can now copy column "E" and then paste that into your SQL Management Studio and run. For simplicity sake, here are a few rows from the actual Excel file that is attached to this post.

INSERT INTO dbo.Locations(LocationName, Address, City, State, Zip) VALUES ('1385 Metropolitan Ave (UCO)', '1385 Metropolitan Avenue', 'Bronx', 'NY', '10462')
INSERT INTO dbo.Locations(LocationName, Address, City, State, Zip) VALUES ('Whitestone', '138-11 20th Avenue', 'Whitestone', 'NY', '113562451')
INSERT INTO dbo.Locations(LocationName, Address, City, State, Zip) VALUES ('Target Flushing T-1150', '13505 20th Ave', 'Flushing', 'NY', '11356')
INSERT INTO dbo.Locations(LocationName, Address, City, State, Zip) VALUES ('LGA - Delta Flight Ctr-Delta Term', 'La Guardia International Airport', 'Flushing', NY', '11371')
INSERT INTO dbo.Locations(LocationName, Address, City, State, Zip) VALUES ('Flushing - Main Street', '41-02 Main Street', 'Flushing', 'NY', '11372')

Then execute your script and you're on your way.


Conclusion

When is it appropiate to use this method? IT DEPENDS. If you have 10 records, no. If you have 1000 records? Yes. Its all about productivity. Ask yourself, is it going to be faster for me to spend 5 minutes writing this in EXCEL or is it going to take me 5 minutes to import them manually? This is up to you to answer. Hopefully this helps you on your next project. :)

Download File

starbucks-locations-xls.zip (52.71 KB)

kick it on DotNetKicks.com
#    Comments [0] |
 Saturday, March 17, 2007

HOWTO: Build a Store Locator in ASP.NET

Full Visual Studio 2005 solution included at the bottom of this post.

Many organizations have multiple locations throughout the country. A lot of the time the organizations customers will want to know where the closet location of that store is. We’ve all become accustomed to going to a companies website and finding the store locator and locating the store that’s closest to us. This is a simple thing for a user to do. But building a store locator is far from simple and can become quite complex, real quick. I’ve put together a simple example that will enable you to add store locator functionality to your ASP.NET website in no time.

Let’s start by covering the basics….

Requirements for store locator functionality: 
   - Database to store your store locations
   - Each store location needs a Longitude / Latitude 
   - A method to retrieve Latitude / Longitude, also known as Geocoding
   - A Web Front end that allows users to search and view the results.

Screen Shots

Search Screen:

Results Screen (click for larger view):

 

The Database

The database is very simple. We have one table, two sprocs, and 3 functions. It is in the App_Data folder of this solution.

The Location table holds the store locations.

The GetNearbyLocations sproc gets the locations that are closest to the user through a mathematical calculation that is inside of the sproc.

The InsertLocation sproc inserts a new location into the Location table (we’ll get to that near the end).

The three functions: XAxis, YAxis, ZAxis are used in the distance calculation that is inside of the sproc.

Important Note: I’m not the genius that wrote this mathematical calculation. Therefore, I can’t take credit for it. The database table, functions and distance sproc are all modeled after this post on MSDN. I have altered quite a few things especially the GetNearbyLocations sproc where I actually calculate the Earths X,Y, and Z axis’ at runtime. 

 

The Geocoding – Getting the Latitude / Longitude

The latitude and longitude are needed to perform the distance calculation in the GetNearbyLocations stored procedure. The Latitude and Longitude of each store is stored in the Locations table (see the database image above) with the location record itself.

How to do we get the Latitude / Longitude?

That’s where the Google Maps API comes into place. Google Maps allows you to sign up for a free API key.

Important Note: If you are going to test this locally, you will need to get a API key that is associated with your local machine, e.g.: http://localhost:port/  where “port” is your port number, such as: localhost:4688, localhost:1637, etc).

Where put your Google Maps API Key
The key is located in two places (I know, its not best practice) but, it’s the only way I could get it to work without spending hours on figuring it out. It’s located in the web.Config and in the Default.aspx page.

Default.aspx page (click for larger view)

web.Config

In a previous post I had built a class that retrieved the latitude and longitude of an address. By using this class while a new location is being added, (AddNewStore.aspx), the Lat/Lon coordinates are then retrieved and saved.

protected void addNewStoreButton_Click(object sender, EventArgs e)
{
   string address = String.Format("{0}, {1}, {2} {3}"
   addressTextBox.Text,
   cityTextBox.Text,
   stateTextBox.Text,
   zipTextBox.Text);
   Coordinate addressCoordinates = Geocode.GetCoordinates(address);
   ... // Other code ommitted
}

The Web Front End

The web front end is simple (errrrrrrr… kind of). The application requires 2 things:
1. An address
2. A distance to search within.

The user enters this information, it’s passed to the database, the calculation is performed and the records that match the distance compared to the address are returned. Simple, right?

Now its time for the “somewhat” confusing part: the task of integrating the Google map with clickable markers. Google doesn’t offer markers that are numbered (from what I could find). So I found some on the net and included them in this project. Which leads me to the next point…

A maximum of 100 results will be returned.

This is set within the stored procedure. The reason we only return 100 records is because we only have 100 icon images (1 through 100). Plus, placing more markers on the page would have a negative impact on the memory and processor on the user’s machine. Furthermore, who’s really going to look at 100 results? The user is probably only looking for the closest couple of stores. Not the top 100.

Google Marker Placement

In order to place markers on the screen we needed lat/lon points to pass to Google’s API. This poses a problem because our data is in the DB, but Google Maps API needs it on the client to process it. Therefore, while on the server, while we have the data in a dataset (below) ...

/// <summary>
/// Gets the store locations and the coordinate for the "from" area (the address the user entered).
/// </summary>
/// <param name="coordinate">A coordinate.</param>
/// <param name="data">A LocationsData dataset.</param>
private LocationsData GetLocationData(Coordinate coordinate)
{
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["StoresDb"].ConnectionString);
connection.Open();

string SQL = "GetNearbyLocations";
SqlCommand command = new SqlCommand(SQL, connection);
command.Parameters.Add(new SqlParameter("@CenterLatitude", coordinate.Latitude));
command.Parameters.Add(new SqlParameter("@CenterLongitude", coordinate.Longitude));
command.Parameters.Add(new SqlParameter("@SearchDistance", distanceDropDown.SelectedValue));
command.Parameters.Add(new SqlParameter("@EarthRadius", 3961)); // In Miles
command.CommandType = CommandType.StoredProcedure;

SqlDataAdapter da = new SqlDataAdapter(command);
LocationsData data = new LocationsData();
da.Fill(data.Location);
return data;
}

GetJSONLocations(LocationsData data);

... we have to create a string representation of a JSON object array that holds all this info, this is done in the GetJSONLocations method. Please see the method for more documentation on how that variable is created.

Info that the JSON object holds: 
   - Location Name
   - Address 
   - Url Encoded Address
   - Latitude
   - Longitude

This info was written to the screen using the RegisterClientScriptBlock.

Using the same method of as before we create another JSON variable (homeSpatialInfo) that holds the “home info”. This info is the address that the user typed in.

This information is used for the popup marker, as well as the link that is provided within the popup marker. Clicking on the “directions” link (within the popup marker) will take you to Google’s map site with the “to” and “from” address parameters already populated, therefore giving you a directional map from the location you typed in, to the location that you clicked on the map. Smooth, eh?

(click for larger view)

 

Adding a new Location

To add a new location, fire up the AddNewStore.aspx page and type in the required info (in this case I’m requiring all fields, but this can be changed to fit your own needs) and submit. If the address cannot be found, (Google Maps API returns “0” for both the Lat/Lon coordinates that it cannot find) it will inform you. Otherwise the address will be added and then upon your next search, it will be returned in the results (if the location is within the distance specified).

 

Database Note: The locations that are in the Stores.mdf that come with this solution are 200 Starbucks stores that are within the New York Area. This is not a comprehensive list, this is just a list I happened to have for testing purposes.


And that’s all folks!

Download and enjoy. :)

StoreLocator.zip (521.92 KB)

kick it on DotNetKicks.com
#    Comments [18] |
 Thursday, March 15, 2007

HOWTO: Debugging JavaScript using "debugger;"

There are a lot of developers who write custom JavaScript or need to debug pre-written JavaScript, yet do not know that they can debug it in Visual Studio 2005. This is a fairly simple process.

Visual Studio offers the developer the ability to utilize the IDE to debug, just like you would debug if you are debugging .NET code. How? Very simple, the "debugger;" key word.

How It Works

First, you must enable script debugging in Internet Explorer (we will get that in a minute, first lets look at some code).

To debug: Write your JavaScript and place the "debugger" keyword where ever you want the code to break into debugging. The JavaScript interpreter hits this keyword and halts execution and returns the control back to the IDE. This is like setting a breakpoint inside of Visual Studio.

Example

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JsDebuggerExample._Default" %>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
<script type="text/javascript" language="javascript">

var myJsonVar = {
firstName : "Donn",
lastName : "Felker"
};

debugger; // The code will break right here and return to the IDE for you to debug.

</script>
</head>
<body>
<form id="form1" runat="server">
<div>

</div>
</form>
</body>
</html>

This will allow you to break into the code. When control returns to the IDE, it looks like this:

 

How To Enable in Internet Explorer

You'll need to uncheck a few boxes in the advanced section of Internet Explorer to enable script debugging. If you dont, script debugging simply wont work. It will not break and you'll be left scratching your head wondering what you did wrong.

Go to Internet Options inside of Internet Explorer

Then go to the Advanced Tab and Uncheck "Disable script debugging (Internet Explorer)" and "Disable script debugging (Other)"

Click "Ok".

Now place your "debugger" keyword anywhere in your JavaScript. Fire up the page through Visual Studio and get your debug on.

:)

kick it on DotNetKicks.com

#    Comments [3] |
 Wednesday, March 14, 2007

Notepad++ Shortcuts - Vista 64bit Update

In a previous post I gave an example of how to run Notepad++ from the command line by typing the letter n. This was the solution for Windows XP. Shortcutting the name is a tip I learned from Scott Hanselman, check out his blog for tons of other good stuff.

I recently upgraded to Vista (x64) and found out that my reg edit wouldnt work any more so I created a new one.

You can use this new reg edit to run Notepad++ from the command line in Vista (x64).

Code 

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\n.exe]
@="C:\\Program Files (x86)\\Notepad++\\notepad++.exe"

 

Shell Integration

Notepad++ does not install shell integration in Vista (x64 in my case) so I created another registry entry for this as well. This will enable the right click and selection of "Notepad++" into the windows context. Like this:

Download the shell integration file belwo.

 

Downloads
'n' Shortcut: n.zip (.31 KB)

Shell Integration:

vista_x64_notepadpp_shell_integration.zip (.34 KB)
#    Comments [5] |
 Monday, March 12, 2007

C# Google Geocode (Latitude and Longitude) Class

Update 2007/05/07: There is also a Microsoft MapPoint v4.5 project I've written that does the same thing. Click here to go to that post.


Retrieve the Latitude and Longitude of any addresses in the United States, Canada, France, Germany, Italy, Spain and Japan (link) with this class. View the class below and download the class at the bottom of this post.

Code


using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Net;
using System.Web.UI;


namespace GoogleGeocoder
{
   public interface ISpatialCoordinate
   {
      decimal Latitude {get; set; } 
      decimal Longitude {get; set; } 
   }

   /// <summary>
   /// Coordiate structure. Holds Latitude and Longitude.
   /// </summary>
   public struct Coordinate : ISpatialCoordinate
   {
      private decimal _latitude; 
      private decimal _longitude;

      public Coordinate(decimal latitude, decimal longitude)
      {
         _latitude = latitude;
         _longitude = longitude; 
      }

      #region ISpatialCoordinate Members

      public decimal Latitude
      {
        get 
        { 
            return _latitude; 
        }
        set 
        { 
            this._latitude = value; 
        }
      }

      public decimal Longitude
      {
        get 
        { 
            return _longitude; 
        }
        set 
        { 
            this._longitude = value;
        }
      }

   #endregion
   }

   public class Geocode
   {
      private const string _googleUri = "http://maps.google.com/maps/geo?q=";
      private const string _googleKey = "yourkey";
      private const string _outputType = "csv"; // Available options: csv, xml, kml, json

      private static Uri GetGeocodeUri(string address)
      {
         address = HttpUtility.UrlEncode(address);
         return new Uri(String.Format("{0}{1}&output={2}&key={3}", _googleUri, address, _outputType, _googleKey));
      }

      /// <summary>
      /// Gets a Coordinate from a address.
      /// </summary>
      /// <param name="address">An address.
      /// <remarks>
      /// <example>1600 Amphitheatre Parkway Mountain View, CA 94043</example>
      /// </remarks>
      /// </param>
      /// <returns>A spatial coordinate that contains the latitude and longitude of the address.</returns>
      public static Coordinate GetCoordinates(string address)
      {
         WebClient client = new WebClient();
         Uri uri = GetGeocodeUri(address);


         /* The first number is the status code, 
         * the second is the accuracy, 
         * the third is the latitude, 
         * the fourth one is the longitude.
         */

         string[] geocodeInfo = client.DownloadString(uri).Split(',');

         return new Coordinate(Convert.ToDecimal(geocodeInfo[2]), Convert.ToDecimal(geocodeInfo[3]));
      }

   }
}


How To Use


  1. Replace "yourkey" with your google api key. Get one here.
  2. Include in your project, reference the class through a using directive.
  3. Call get the coordinates like this:
    1. Coordinate coordinate = Geocode.GetCoordinates("1600 Amphitheatre Parkway Mountain View, CA 94043");
      decimal latitude = coordinate.Latitude;
      decimal longitude = coordinate.Longitude;

Uses


For each record in your system, get the lat/long and save it to the database. This can be used for calculating distances. e.g.: "Find all stores within ___ miles of this zip code.

 

***Notes***


The maximum # of Geocode requests that can be completed in one day are 50,000 (details).

 

Download
Geocode.zip (1.05 KB)

kick it on DotNetKicks.com
#    Comments [20] |

aspnet_wp.exe could not be started?

I got this odd error message from an internal web service today that stumped me for ~30 minutes. It was:

"aspnet_wp.exe could not be started. The error code for the failure is 80070545. This error can be caused when the worker process account has insufficient rights to read the .NET Framework files. Please ensure that the .NET Framework is correctly installed and that the ACLs on the installation directory allow access to the configured account."



I took a look on some forums and blogs and other users who encountered this error said that they checked permisisons on the framework, the temp directory, the ASP.NET Temp directory and the application path. I did the same. Everything was ok, but the app was still broken. Other users said to uninstall and reinstall .NET 1.1 and that fixed it. I didn't think that was necessary.


How to fix it...

I did some more poking around and noticed that the .NET framework that was executing this was 1.1. It should have been 2.0. Like below:


 

 

***Update***:  This problem still intrigued me, so it was looked into some more. It seems that some how a recent install (either WSE 3.0 or AJAX) has caused an issue. All of our 1.1 apps were not responding. Because this server we were working with is a testing box we were able to elevate the permisisons of the ASPNET user higher than "user" and the apps started working again. We elevated the ASPNET user to "Administrator" for the time being. We plan to replace this box in the very near future (few weeks) so its not that big of an issue for us since only developers have access to the system, and, well, its a test system. :) Please note, this is not a desirable thing to do in a production environment.

#    Comments [0] |
 Saturday, March 10, 2007

Open Source .NET Wiki

I've been on the hunt for a good .NET wiki that was open source and I think I've finally found one. The folks over at ScrewTurn Software have developed ScrewTurn Wiki.

Its GPL'd, built on .NET 2.0, does not require SQL Server 2005, works in a medium trust enviroment (that means that you hosted types can use it!) and has many other features which are listed here. The only two things that you'll need are:

  1. IIS5 (or better) with .NET 2.0 installed.
  2. One write enabled directory in the root of the wiki

 

If you need to see it in action, check out the .NET Tiers website. The guys over at .NET Tiers are also using this for their site.

This is definately something that can come in handy in the corporate world when you don't have something like SharePoint installed (which offers built in Wiki support).

 

kick it on DotNetKicks.com
#    Comments [2] |
 Friday, March 09, 2007

Visual Studio SP1 with Vista


 

At work, we just upgraded our machines to Quad Xeon x64 machines with four gigs of ram. NICE..... :) But for some reason the manufacturer loaded 64 bit XP, even though we requested Vista. We upgraded it to 64 bit Vista quite easily, problem solved.

I did run into an issue while installing Service Pack 1 for Visual Studio 2005. I was attempting to install the SP1 Vista Update and I kept getting this error that told me that the proper "patches" were not in place, therefore the SP1 Vista Update would not install. To resolve this error you have to actually install SP1 (the regular one) and then the update. IMHO the documentation isnt that great in this area, I got confused...  See for yourself:

"For developers using Visual Studio 2005 on Windows Vista, Microsoft provides an update to Service Pack 1 called Visual Studio 2005 Service Pack 1 Update for Windows Vista. This update builds on the improvements made in SP1 and delivers a first class experience for developers wanting to take advantages of the new features in Windows Vista."

I was taking this as "this is the SP if you're on Vista".

So... to upgrade to SP1 on Vista... do the following:

1. Install SP1

2. Instal The SP1 update for Vista

3. Get you're code on...

#    Comments [0] |
 Monday, March 05, 2007

Tree Surgeon - .NET 2.0 Reference Incorrect

Problem

The .NET Framework reference in the most recent release of Tree Surgeon has an old reference to .NET 2.0 Beta 1. This is in the NAnt.exe.config file.

This will produce results that will not compile when using the <msbuild> task of the NAntContrib Tasks.

Fix

Open the file located in "ProjectName/Tools/nant/NAnt.exe.config" file.

Find this:

<framework 
   name="net-2.0" 
   family="net" 
   version="2.0" 
   description="Microsoft .NET Framework 2.0 Beta 1" 
   runtimeengine=""
   sdkdirectory="${path::combine(sdkInstallRoot, 'bin')}" 
   frameworkdirectory="${path::combine(installRoot, 'v2.0.40607')}" 
   frameworkassemblydirectory="${path::combine(installRoot, 'v2.0.40607')}"
   clrversion="2.0.40607"
>

Then replace it with this:

<framework 
   name="net-2.0" 
   family="net" 
   version="2.0" 
   description="Microsoft .NET Framework 2.0" 
   runtimeengine=""
   sdkdirectory="${path::combine(sdkInstallRoot, 'bin')}" 
   frameworkdirectory="${path::combine(installRoot, 'v2.0.50727')}" 
   frameworkassemblydirectory="${path::combine(installRoot, 'v2.0.50727')}"
   clrversion="2.0.50727"
>

This will fix the issue and allow you to remove the <solution> task from the default build file that is included in each project generation.

You will now be able to utilize the <msbuild> task in the NAntContrib. See below:

<target name="compile" description="Compiles using the AutomatedDebug Configuration">
        <loadtasks assembly="tools/nantcontrib-0.85/bin/NAnt.Contrib.Tasks.dll" />
        <msbuild project="src\MyProject.sln">
            <property name="Configuration" value="AutomatedDebug" />
        </msbuild>
</target>

#    Comments [0] |
 Friday, March 02, 2007

Running Notepad++ From the command line

I've been using Notepad2 for quite awhile now and was recently introduced to Notepad++. I love saving time by launching Notepad2 by typing "n" into the command line. I save all the "otepad"s through the day. Its small, but hey, I learned it from Scott Hanselman, aka: the master of productivty.

After installing Notepad++ I realized I would never use it unless I could launch it with the same quick draw speed as of my favorite Notepad2. I had to type "Notepad++" in the command window to get it going. No! I had already eliminated the "otepad" and now I had two more characters on that same annoyance.

I fixed that annoyance by making a change to this registry key ...

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Notepad++.exe]

I was able to change it to "nn" (yes, I'm still secretly attached to Notepad2 as we speak, but I'm weaning off of it). Now, I can fire up Notepad++ through the command line with a quick "nn".

Here's the registry file if you want to do it yourself.

Download

Notepad++RunFromLettersNN.zip (.35 KB)

#    Comments [0] |

Gemini Webservice interacting with SharePoint Business Data Catalog

At work we use the Gemini Project Issue Tracker every day. We've a very small team, so we're able to get away with the free license for now. Upper management reviews the status of tickets and bugs and the overall status of any project at any given time. We also use SharePoint to collaborate and share documents throughout our company. We recently upgraded to MOSS 2007 (SharePoint 2007) and with this install comes the Business Data Catalog (BDC). This allows us to link back end systems to MOSS. MOSS provides a good toolset of web parts that YOU DO NOT have to write yourself. If your application exposes a web service or database connectivity, MOSS can consume. This means tons of development time, saved, IF. you can figure out how to write the BDC Application MetaData (XML).

I decided that we should try to implement Gemini into MOSS. Again, to my dismay I had to write some really nasty looking XML, this is the "Application MetaData". The documentation on the BDC MetaData Model isnt that "great" (IMHO) and its difficult and frustrating to write the XML MetaData. Who wants to sit around and write XML all day anyway? bleh. Boring...

I got MOSS to connect to Gemini through the webservice. This example only displays a few actions to prove that we can get data from Gemini.

It allows you to select a Project ID (int) and then the actions of "View Project" and "Open Gemini" will be presented.

How To

To get this to work, you'll have to replace this text: http://PathToYourGeminiSite/webservices/gemini.asmx?WSDL with the actual path to your Gemini Site.

Then import it into your BDC and use the Business Data Action Web Part to display the data.

Screen shots

Application Metadata Info Page

Page as user sees it once the web part is live.

Clicking the "View Profile" link will allow you to see data that is returned from the Web Service (as seen below):

Clicking "Open Gemini" will take you to the Gemini home page in a new window. Clicking "Open Project" will open that projects page in a new window.

Download the MetaData File.

GeminiMetadata.zip (1.07 KB)

#    Comments [0] |