.NET Discussion

.NET Issues, Problems, Code Samples, and Fixes

ASP.NET, PayPal, and Google Checkout: The Solution!

After searching high and low for a solution to the PayPal/Google Checkout dilemma (trying to submit your shopping cart to them using ASP.NET was a problem because you couldn’t use nested forms), I have come up with a (non-kludgy) technique that will work, and actually provides the developer with another level of abstraction that could potentially be useful elsewhere.

EDIT: 2/27/2008 – There is a much better way to integrate PayPal and Google Checkout. Please see my new article, ASP.NET: How To Integrate Both Google Checkout and PayPal In 3 Steps. The article on the page you are currently viewing should be used as a reference on how to nest MasterPages.

What’s this technique? Nested MasterPages, of course! Here’s what I did step by step:

  1. Create a wrapper MasterPage that includes everything that will be common on all of your pages except for your <form> tag
  2. Create a ContentPlaceHolder inside your wrapper MasterPage
  3. Create a child MasterPage that calls the wrapper as its MasterPage
  4. Inside the child’s <asp:Content> tag, put your form
  5. Once you’ve placed your form inside your child MasterPage’s content tag, create a ContentPlaceHolder, and then add a content page (.aspx page)

Be sure to reference your wrapper from your child MasterPage’s page directive, like so:
<%@ Master Language="VB" MasterPageFile="~/masterWrap.Master" CodeFile="masterChild.master.vb" Inherits="masterChild" %>

Once you’ve set up this level of abstraction, you can create another child master page without the <form runat="server"> tag in it, and do all your necessary PayPal and Google Checkout form construction! I usually use literals to create the forms and their hidden fields on the server side.

I created this abstraction very easily in about five minutes in an application that was using MasterPages already, so it’s not hard to retrofit if you need to. Remember also that a child can only reference its direct parent (and that MasterPages render LAST!), so if you need pass info to your wrapper MasterPage, create properties in the MasterPages up the line and pass them along in the Page_Load subroutine (don’t forget to set up MasterPage referencing).

So for those of you looking for a method to use PayPal and Google Checkout within your current MasterPage setup, this may solve your woes! It solved mine!

NOTE: By doing this, you will lose design-time support in (at least) Visual Studios 2005, since it does not support nested MasterPages in design mode. I guess everything comes with a price.

kick it on DotNetKicks.com

September 28, 2007 Posted by | ASP.NET, Google, MasterPages, PayPal, Tips & Tricks | | 34 Comments

ASP.NET and AJAX: New AJAX Toolkit Release! (10920)

A few days ago, Microsoft released the newest version of the AJAX Toolkit (10920)! Go check it out, download, and install in your Visual Studios.  A lot of old bugs were fixed in the “Calendar, PopupBehavior, AutoComplete, Accordion, ConfirmButton, ModalPopup, MaskedEdit and Slider”, so this release should prove to be the best one yet (as most new releases are).

September 27, 2007 Posted by | AJAX, AJAX Toolkit, ASP.NET, Bugs, Tips & Tricks | Leave a comment

ASP.NET: GridView Update/Edit/Cancel, HyperLinkFields, and DataKey Retrieval

Today was spent mostly tackling the GridView’s Update/Edit functionality, and I got incredibly frustrated, at first. This was my first foray into this part of the GridView’s functionality, since I haven’t really had to develop anything using it since the switch to 2.0, as everything in DataGrids still functioned fine. With a little bit of research, a lot bit of patience, and some help from the internet community, I was able to solve all my issues, and pretty elegantly at that.

Basically, I was trying to convert an existing data-display-only GridView (ie, no special functions) into one where I can update a field, namely the inventory for displayed products. After working with DataGrids so efficiently, I was scared that GridViews were going to be a million times more complex. I suppose my eyes got big when I saw all the new properties and methods, and wanted to try them all out.  Big mistake.

Most articles I found were for hardcoded datasources (especially on MSDN, ugh) and didn’t really help me much, so this post will be referring to GridViews with dynamically bound datasources. First, create a GridView with three bound columns and an Update/Edit/Cancel (CommandField) column:

<asp:gridview id="GridView1" runat="server" autogeneratecolumns="False" onrowediting=GridView1_RowEditing datakeynames="productid" onrowcancelingedit=GridView1_RowCancelingEdit onrowupdating=GridView1_RowUpdating>
       <columns>
       <asp:hyperlinkfield datanavigateurlfields="productid" datanavigateurlformatstring="/products/index.aspx?productid={0}" text="Product" target="_blank" />
        <asp:boundfield datafield="inventory" headertext="Inventory" />
        <asp:commandfield showeditbutton="True" />
        <asp:boundfield datafield="productid" visible="false" />
       </columns>
      </asp:gridview>

Nothing in there should be shocking to anyone: all your events are handled, you have a HyperLinkField that uses the DataNavigateURLFields property to insert a ProductID, and you have set your DataKeyNames property to your hidden field which holds your ProductID.

Because we are not using the GridView’s built-in data model and are binding dynamically, the GridView will not switch into and out of Edit Mode automatically. Thus, in order to switch it into Edit Mode, in each of your event handles (RowEditing, RowUpdating, and RowCancelingEdit) you must do two things:

  1. Change the GridView’s EditIndex appropriately
  2. Re-bind your GridView

These are both very easy to do, and your RowEditing and RowCancelingEdit handles should be simple, like this: 

Protected Sub GridView1_RowEditing(ByVal sender As System.Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs)

GridView1.EditIndex = e.NewEditIndex 'set to selected row
BindGridView() ' your own subroutine that you use to bind your datagrid

End Sub

Protected Sub GridView1_RowCancelingEdit(ByVal sender As System.Object, ByVal e As System.Web.UI.WebControls.GridViewCancelEditEventArgs)

GridView1.EditIndex = -1 'set to no selection
BindGridView()

End Sub

One issue I ran into while attempting to figure this all out was if I didn’t rebind my GridView at the end of each event, I was required to click twice to get it to select the correct row, and if I clicked around, it would always be a row behind. So be sure to rebind your GridView at the end of your event handler. 

The RowUpdating event is where it gets tricky, since pulling values is not necessarily intuitive. You can’t do something like GridView1(i)(j).Text = str or anything even close. Instead, you must cast the cells as controls. Here’s an example of how I did it in my RowUpdating event handler:

Dim name As HyperLink
Dim inv As TextBox

name = CType(GridView1.Rows(e.RowIndex).Cells(0).Controls(0), HyperLink)
inv = CType(GridView1.Rows(e.RowIndex).Cells(1).Controls(0), TextBox) ' .Cells(1) refers to the 2nd column

Once you’ve casted them, you can now easily get their values by invoking their .Text property, ie, name.Text. Remember that my first column was a HyperLinkField, so in order to pull that value, I must cast that column as a HyperLink.

Finally, to pull your hidden value that you’ve dubbed a DataKey in the GridView’s DataKeyNames property, do the following:

Dim ProductID as Integer = GridView1.DataKeys(e.RowIndex).Value

EDIT 3/5/08: I forgot to mention in this article how to retrieve “Read-Only” data. You cannot convert a read-only cell into a textbox, so you must retrieve the value another way:

Dim str as String = GridView1.Rows(e.RowIndex).Cells([your cell]).Text

Then do whatever you need to do to update your database, set the EditIndex to -1, and call your BindGridView() subroutine. Everything should be sorted out when the “Update” link is pressed. To enhance this process, be sure to include your GridView in an AJAX UpdatePanel.

Hope this saves someone a full day of research (and possibly some hair)!

kick it on DotNetKicks.com

September 26, 2007 Posted by | AJAX, ASP.NET, GridView, Tips & Tricks | 148 Comments

ASP.NET GridView: How To Add A HyperLinkColumn Dynamically

I have been searching all over the web for a way to do this, and it doesn’t appear as if anyone else knows! How do you add a HyperLinkColumn to a GridView dynamically at runtime? If this isn’t possible, is there a way to modify its properties? I can’t seem to access the HyperLinkColumn to modify the Target property, which doesn’t seem right.  Shouldn’t you be able to access any property programmatically?

Status: Solved! (10/23/07)
Solution: See comment by Kevin Brock. Thanks, Kevin!

September 24, 2007 Posted by | ASP.NET, GridView | | 13 Comments

ASP.NET and MySQL: How To Build A Search Engine For Your Website In 3 Steps

About a year ago I built a fully-functioning search engine for my website, Columbus Supply. It took me all day to figure out the SQL syntax, but afterwards, I was very pleased with the results.  MySQL has very powerful search capabilities with the MATCH() and AGAINST() functions when used in conjunction with the FULLTEXT attribute. Using these, MySQL determines a “score”, which is a relative relevancy to the search query. 

The technique I used requires a few queries, but only one call to the database if all the queries are strung together and sent at once (separated by semicolons, of course 🙂 ). First, create a temporary table with all the necessary columns from all your different existing tables:

CREATE TEMPORARY TABLE temp1 (PlayerID INT, Name TEXT, Age INT, Biography TEXT, FULLTEXT (Name, Biography)) ENGINE=MyISAM;

Then fill your temp table with all the data from your tables. Be sure to do any replacing and concatenation here:

INSERT INTO temp1 (PlayerID, Name, Age, Biography)
SELECT PlayerID, Name, Age, REPLACE(Biography,'</p><p>')
FROM tblPlayers;

Now you are going to do a SELECT statement against that table for all the columns you want. The real magic happens in the WHERE clause:

SELECT *
FROM temp1
WHERE MATCH(Name, Biography) AGAINST ('YourSearchString')

Remember how we declared ‘Name’ and ‘Biography’ as FULLTEXT? Here’s where that comes into play. You are selecting everything, but you are comparing against the columns you deemed as FULLTEXT. With the MATCH() and AGAINST() functions in the WHERE clause, the results are automatically ordered by relevancy. If you want to see the actual relevancy, just include your MATCH() and AGAINST functions in the SELECT statement using AS to name it something, like “score”.

And that’s it! You can take those results and populate a GridView or any other control. It can get complex with all the unions and joins from all your tables, but this is the concept that I came up with. It has served me well, and my results are relatively accurate. You can extend this further with filtering in your WHERE clause, such as WHERE Age=24 AND MATCH(...

NOTE: This will not return a result for some queries for various reasons, including but not limited to: the use of common words that MySQL has deemed semantically negligible, searches of three letters or less, or searches where the search string appears in 50% or more of the records in the particular dataset you are pulling from, ie, your temp table.

In the instance where a search is three letters or less, you can do the first two steps as usual, and in the last step, instead of using MATCH() and AGAINST(), use LIKE like so:

SELECT *
FROM temp1
WHERE Name LIKE '%YourSearchString%' OR Biography LIKE '%YourSearchString%'

Granted, this will result in a much less accurate recordset, but it will still yield some relevant records, which may be enough for your user. They did, after all, enter a three-letter-or-less query!

More reading on this technique: Full-Text Search | Fine Tuning Full-Text Searches

Hope this helps someone out there!

September 20, 2007 Posted by | ASP.NET, GridView, MySQL, Tips & Tricks | 4 Comments

ASP.NET: How To Build A Silverlight Application

Well, I’ll tell you, I don’t think I will be building one any time soon, as I don’t think I have the time to learn about it, but after a cursory peek across the web, I’ve found some really really interesting stuff about this exciting new technology.  First, you will need to download the appropriate SDK’s etc. and install them in your Visual Studios.  In Scott Gu’s blog, he has a link to a video of him demonstrating how to build a Silverlight product from scratch.  I’ll admit, I got kind of lost a bit at the end, but I also don’t consider myself a super-advanced .NET programmer, either. 

Maybe one day I will have the need and the budget to build a Silverlight project, but for now I will just gawk at the ones you guys are creating.  I’ve always liked Flash’s interactivity and potential for extremely cool GUIs, but I hated the fact that the ActionScript changed every year or so, and that they were not compatible with each other. The fact that Silverlight can be built and configured in Visual Studios using .NET languages is fantastic, and really leads to a lot of developers being able very easily to create awesome GUIs.  Definitely a step up on Flash, at least from the developer’s perspective. With the ability to use ExpressionBlend (which I haven’t used, only seen from this demo video above) seamlessly with Visual Studios, it appears the possibilities are not only endless, but easy to achieve!

If you’re building a Silverlight application, post it here!  Depending on the response, I will create a page (like my About page) featuring my readers’ Silverlight apps.

September 7, 2007 Posted by | ASP.NET, Silverlight, Tips & Tricks | Leave a comment