Monday, December 13, 2010

How to Set MasterPage Variables from Content Page

Need to send information from your content page to your master page?
Despite what you may have read on a couple blogs, IT CAN BE DONE!
Here's how.

Suppose I have a variable in my code behind my master page that I want to set based on what content page is opened. In my particular case, I'm going to use an example of a menu that I will only show while browsing certain pages in my website.

The first thing I need to do is create a variable within my master page:
Private _showMenu As Boolean = False

I can use this variable later within my master page's Me.Load function to set the menu control to visible or not. Now, I need a way to interact with the Master page for this variable, so I will make a simple Property for the page:
Public Property ShowMenu() As Boolean
Get
Return _showMenu
End Get
Set(ByVal value As Boolean)
_showMenu = value
End Set
End Property


We are now done with the MasterPage, which for my example I have named "MyAwesomeMasterPage". Moving on to content pages, for each page I want to communicate with my master page, all I have to do is add one easy line in the initialization of the page. I do it so early, just in case I need to access the variable early in my master page's loading.
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
CType(Master, MyAwesomeMasterPage).ShowMenu = True
End Sub


By casting my content page's masterpage as the MyAwesomeMasterPage page that I created, it is now aware of the Public Property that I created for it.

Friday, December 3, 2010

How to handle GoDaddy's preinstalled URL Rewrite when running code locally

This blog assumes that you are either taking advantage of the Microsoft URL Rewrite module on a GoDaddy hosting server or another hosting server that has URL Rewrite preinstalled. If you have questions about how to use this module on GoDaddy, then click here to read one of my previous blogs that goes more into detail on how to implement the module.

If you are using the GoDaddy pre-installed URL Rewrite module on your site, and testing changes locally, you've probably run into a couple problems when you attempt to go to a url utilizing the rewrite method.

For example, if my site has user profiles that can be accessed with a unique ID the user chooses, a profile URL might look like this:
http://www.digitalplaydoh.com/RobFine

Behind the scenes, my URL Rewrite method looks something like this:
<rewrite>
<rules>
<rule name="RewriteCheck" stopProcessing="true">
<match url="^(.+)$"/>
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true"/>
<add input="{URL}" pattern=".*.axd$" negate="true"/>
</conditions>
<action type="Rewrite" url="MyProfile.aspx?key={R:0}"/>
</rule>
</rules>
</rewrite>


On GoDaddy's servers, this will execute perfectly however, while I'm debugging the code on my local machine, the URL Rewrite module is not available, meaning I constantly get a Server Error when I try to go to http://www.digitalplaydoh.com/RobFine yet when I go to http://www.digitalplaydoh.com/MyProfile.aspx?key=RobFine everything works fine.

There is a solution!

I have created a function within my Profile class called ProfileURL that I use to return the url for a particular profile. I originally created it to handle cases where users had not chosen a unique ID, but now it's going to help us develop locally as well.

The original function looked something like this:


If there is a unique ID for the user, it will send the unique id back as the url.
If there is no unique ID established, it will send back the profile page MyProfile.aspx and feed in my Profile ID.

It is important that anytime I feed my Profile URL to a link, I call this function.

Now, I need to add a bit to the function to support when I'm debugging locally. In the case of the "RobFine" profile earlier, this profileURL will still return just "~/RobFine" as it stands now. What I can do is add in a simple IF THEN statement to check if we are running locally:
Public ReadOnly Property ProfileURL() As String
Get
If HttpContext.Current.Request.IsLocal Then
Return "~/MyProfile.aspx?id=" & _id
Else
If Not _uniqueID = "" Then
Return "~/" & _uniqueID
Else
Return "~/MyProfile.aspx?id=" & _id
End If
End If
End Get
End Property


HttpContext.Current.Request.IsLocal will return a boolean function if my code is running locally.
If it is running locally, I want to throw back a URL that doesn't implement the URL Rewrite.
If it is not, then I'll have the function act as it normally would on the server.

Wednesday, December 1, 2010

Handling Line Breaks with FQL in ASP.NET

Facebook's FQL query language lets you do some really cool things as far as pulling data from Facebook profiles, events, groups and more. I've been using it lately to create fun websites for various events I've been hosting, but I ran into a small issue while pulling the wall posts from a Facebook Group.

I was able to pull everything from the wall, but it all came as one long string with no html line breaks <br/>. Seems simple enough to fix, right? I ususally append a .Replace(vbCrLf, "<br/>") to my string and I'm golden, but that wasn't working this time.

I tried everything I could think of: vbCrLf, Environment.NewLine, \n, \r\n, \r, Chr(13), PHP_EOL, ControlChars.NewLine, ControlChars.CrLf - nothing seemed to be working until I finally tried out vbLf

The vbLf constant represents \n just as vbCr represents \r and vbCrLf represents \r\n. Facebook uses the \n notation to store line breaks.

So if I were to store my FQL (Facebook Query Language) query results in a string called myFqlResult, I could print it out to the screen in a decent viewing manner with the string:

lblMyExample.Text = myFqlResult.Replace(vbLf,"<br/>")

Facebook also throw in all sorts of xml structures as well, so I usually filter it all out with something like this:
lblMyExample.Text = myFqlResult.Replace("<message>", "<p>")_
.Replace("</message>", "</p>")_
.Replace("<stream_post>", "<div>")_
.Replace("</stream_post>", "</div>")_
.Replace(vbLf, "<br/>")_
.Replace("<fql_query_response xmlns=""http://api.facebook.com/1.0/"" _
xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" list=""true""><br/>", "")_
.Replace("</fql_query_response><br/>", "")_
.Replace("<?xml version=""1.0"" encoding=""UTF-8""?><br/>", "")_
.Replace("<div><br/>", "<div>")

CSS Consistency Issue between IE7 and IE8

While I was creating a short menu out of a bullet list, I observed an inconsistency in padding that surface between websites being viewing Internet Explorer 6 or 7 and Internet Exporer 8.

With IE 8, when I set the margins of my <ul> tags and my <li> tags to 0px, the bulleted list is still indented.


However, with IE 7 and 6, when I set the margins to 0px, the list lines up with the text above it.


From my research and testing, it would appear there is no way to correct for this.
It especially becomes a problem when developing in IE 8 and correcting the margin-left to -30px.
While IE 8 will show the text of the list left aligned with the rest of the text on the page, previous versions of the browser will bleed the list far left beyond the placement of the control's container.


To avoid this problem, the best practice going forward for the next couple years is either to account space for the list to be indented or avoid using lists.

    Monday, November 22, 2010

    Best Validation Expression for Email Address

    If you've been playing around with the ASP.NET Regular Expression Validator or any other RegEx tools, then you've more than likely had to check an email addresses for its validity at some point.

    Email Address values can range all over the place, which makes them somewhat difficult to correctly validate, especially because you don't want someone to not be able to complete a form if their email address doesn't comply with the regular expression you've chosen, or worse, you don't want someone to input an incorrect email address to abide by your validation expression.

    I've been testing various expressions that I've been hunting down across the internet and I've found what I believe the be the best on the simple url: http://www.regular-expressions.info/email.html

    This site addresses the RFC 2822 standard and makes some minor tweaks to it, leaving you with two options. The better of which is [a-z0-9!#$%&'*+/=?^_`{}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}comorgnetedugovmilbizinfomobinameaeroasiajobsmuseum)\b

    However, the above expression does require constant review, as it specifically spells out the top level domains. As new domains are created, they will need to be added to this list. So, tomorrow if the new top level domain was created .webdev (i.e. rob@digitalplaydoh.webdev) then, you would need to add webdev to this expression to allow for all email addresses to be valid.

    Rather than constantly need to check on these top-level domains, I much prefer a tweaked version that allows for a much less strict set of top-level domains, including those that don't exist such as rob@digitalplaydoh.fake. It gives the user the ability to provide a fake email address, but at least I know it's an email address in a proper format.

    Therefore, I find this to be the most accurate email address regular expression:
    [a-z0-9!#$%&'*+/=?^_`{}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?

    Friday, November 12, 2010

    Crossing The Ocean with Google Maps

    Thinking of doing some international travel? Google's got you covered. Did you know that using Google Maps you can plot out directions from Japan to the United State without booking a plane ticket? Follow the directions below to see some of Google's more aggressive traveling suggestions.

    1. Go to Google.
    2. Click on Maps.
    3. Click "Get Directions"



    Now try each of the following Start and End Destinations:

    Start Point: JAPAN
    Destination: CHINA
    Direction #43: Jet ski across the Pacific Ocean
    Link to Directions


    Start Point: JAPAN
    Destination: UNITED STATES
    Direction #38: Kayak across the Pacific Ocean
    Link to Directions

    Start Point: CHINA
    Destination: TAIWAN
    Direction #55: Swim across the Pacific Ocean
    Link to Directions

    See if you can find any other fun modes of transportation modes Google suggests for crossing the ocean.

    Wednesday, November 10, 2010

    Request Variables for ASP.NET Paths, URLs and more

    Rick Strahl has done a great job of outlining which Request variables (Request.RawURL, Request.PhysicalPath, etc) to use for different sections of your site's URL, request variables, web server folder structure and more.

    Click the link below to access his blog post regarding the Request Properties:
    http://www.west-wind.com/weblog/posts/132081.aspx

    Tuesday, August 31, 2010

    Is the Back Button needed on Web Browsers

    A friend recently was ranting about the Back button on a browser and that it often messes up pages he visits. A counterpoint argued that a good developer is always prepared for users to hit the back button and always programs to handle the user trying to go back in time.

    As a web developer, I definitely agree that the Back button is a great nuisance. It also creates a layer of uncertainty in where your user is/came from when they arrive at a page. Anytime a user needs to be able to get back to page they came from, there should be an easily accessible link/button, so is the Back Button really needed?

    I could foresee a lot of malicious intent if browsers didn't have a Back button. Maybe the true problem is how overused or available it is.

    Maybe one alternative would be to present the user with a new tab for every new site (domain) they navigate to and remove the Back button. Each website is now responsible for the navigation around it's own site, yet if you ever pull up something you didn't actually want, you can easily close the tab and you're back at the site that sent you there. It's really just your web history presented different, but it would take up a shit load of memory (depending on the sites you had pulled up). I'm sure other problems would come from such a strategy as well.

    I can't really think of a method that would keep you in full control of web surfing yet remove the Back button entirely. Feels like it might be a necessary evil that developers just have to accept and work around.

    Friday, August 27, 2010

    Nested Gridview Within Another Gridview

    I recently came across a project for which I had a need for a gridview within a gridview.
    For this example, I will create a grids of documents and guides housed within a parent grid of resource categories.

    Let's start with a basic gridview of 4 documents (2 training modules on gridviews and 2 user manuals for cell phones).

    <asp:GridView
    ID="gvDocuments"
    DataSourceID="dataDocuments"
    AutoGenerateColumns="false"
    DataKeyNames="document_id"
    CellPadding="8"
    HeaderStyle-BackColor="#e0e0e0"
    BorderColor="#e0e0e0"
    runat="server">
    <Columns>
    <asp:HyperLinkField
    HeaderText="Resource Link"
    DataNavigateUrlFields="document_filename"
    DataNavigateUrlFormatString="{0}"
    Target="_blank"
    DataTextField="document_name"
    DataTextFormatString="{0}" />
    <asp:BoundField
    DataField="document_description"
    HeaderText="Description" />
    </Columns>
    </asp:GridView>
    <asp:SqlDataSource
    ID="dataDocuments"
    runat="server">
    </asp:SqlDataSource>


    Both could be considered training, but to better organize the page, I will split the documents up into groups, each document having a group column in the database named document_group.
    On my backend, I have a new table to complement the Documents table called DocumentGroups that has a docGrp_name and docGrp_id field. The docGrp_id field will link to the document_group column I mentioned.

    Now to drop my original gridview in a second gridview of "Document Groups"
    This is where the code gets a little more bloated but still relatively simple:
    <asp:GridView
    ID="gvDocumentGroups"
    DataSourceID="dataDocumentGroups"
    DataKeyNames="docGrp_id"
    AutoGenerateColumns="false"
    GridLines="None"
    runat="server">
    <Columns>
    <asp:TemplateField>
    <ItemTemplate>
    <div style="padding-bottom: 12px;">
    <div><%#Eval("docGrp_name")%></div>
    <asp:GridView
    ID="gvDocuments"
    DataSourceID="dataDocuments"
    AutoGenerateColumns="false"
    DataKeyNames="document_id"
    CellPadding="8"
    HeaderStyle-BackColor="#e0e0e0"
    BorderColor="#e0e0e0"
    runat="server">
    <Columns>
    <asp:HyperLinkField
    HeaderText="Resource Link"
    DataNavigateUrlFields="document_filename"
    DataNavigateUrlFormatString="{0}"
    Target="_blank"
    DataTextField="document_name"
    DataTextFormatString="{0}" />
    <asp:BoundField
    DataField="document_description"
    HeaderText="Description" />
    </Columns>
    </asp:GridView>
    <asp:SqlDataSource
    ID="dataDocuments"
    runat="server">
    </asp:SqlDataSource>
    </div>
    </ItemTemplate>
    </asp:TemplateField>
    </Columns>
    </asp:GridView>
    <asp:SqlDataSource
    ID="dataDocumentGroups"
    runat="server">
    </asp:SqlDataSource>


    I added in some padding for better spacing, but you can play around with the CSS however you want.

    Now. I didn't put connection strings or select commands in the original SqlDataSource because, if you don't know what you're doing there, this tutorial is not for you.
    But now that we've embedded this gridview inside another one, that (inner layer) SqlDataSource is more than likely going to be fed a variable from your outer layer grid.
    For my purposes, I'm going to use the docGrp_id, which I conveniently fed into the DataKeys of my outer layer SqlDataSource.
    For more information on pulling the current row's datakey, click here.

    For Each thisRow As GridViewRow In gvDocumentGroups.Rows
    CType(thisRow.FindControl("dataDocuments"), SqlDataSource).SelectCommand = "SELECT * FROM [Documents] WHERE [document_group] = '" & gvDocumentGroups.DataKeys(thisRow.RowIndex).Value & "'"
    Next




    And there you have it!

    Friday, August 20, 2010

    Word Wrap a Label in Windows Form Applications

    I recent was spinning out a quick Windows Form application to help an orders team look up product information and found myself questioning how to wrap text in a label rather than have it venturing off the application into nowheresville.

    As a web developer, I always assume my text will find its place within the boundaries of a panel or table cell, whatever medium houses it. But the same should not be assumed for Windows Forms applications. Luckily, there is a simple solution.

    Set the label's AutoSize property to Off.

    The label becomes a resizable control that you can drag to whatever limits you want the text contained within.

    Thursday, July 1, 2010

    How Google Works

    Ever wonder how Google really works? This is a fun little flow chart published by PPCBLOG that shows you how much goes on behind the plain white background and colorful graphic every second of every day and how fast the Google machine finds new websites, indexes them, rates them and presents them to users searching for a particular string on the internet.

    How Google Indexs Searches Works?
    Click Picture To Enlarge

    Easy Way To Email Errors From Your ASP.Net Site To You

    Errors on your site are never good, but it's best when you know about them the second they happen rather than a user telling you- or worse- not telling you.

    This is a quick a dirty method I use for emailing myself details about errors when they occur on my sites.

    If you don't already have one, add a Global Application Class (Global.asax) to your site. It should come with a sub procedure named Application_Error, but if it doesn't go ahead and create one. In the code I've provided below, I use a custom email class I use to templatize my emails, but you can easily adapt it to any email class you choose.

    Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
    ' Code that runs when an unhandled error occurs

    Dim mm As New MMEmail()
    mm.ToRecipients.Add("")
    mm.Subject = "[ERROR] " & Request.Url.AbsoluteUri.ToString

    Dim ex As Exception = Server.GetLastError().GetBaseException()
    Dim body As String = ""

    'Get URL where error occured
    body &= "[URL]"
    body &= "<br/>"
    body &= Request.Url.AbsoluteUri.ToString
    body &= "<br/>"
    body &= "<br/>"

    'Brief message of what went wrong and line where error occured in code.
    body &= "[MESSAGE]"
    body &= "<br/>"
    body &= ex.Message.Replace(vbCrLf, "<br/>")
    body &= "<br/>"
    body &= "<br/>"

    body &= "[SOURCE]"
    body &= "<br/>"
    body &= ex.Source.Replace(vbCrLf, "<br/>")
    body &= "<br/>"
    body &= "<br/>"

    body &= "[STACK TRACE]"
    body &= "<br/>"
    body &= ex.StackTrace.Replace(vbCrLf, "<br/>")
    body &= "<br/>"
    body &= "<br/>"

    mm.Body = body
    mm.Send()
    End Sub


    Obviously, you'll need to add your email address in and use either the default email class or another class if you'd prefer. You'll need the email to be set up in the web.config - which may be another good topic I could touch on another time. And then, it wouldn't hurt to go intentionally create an error. I made a blank page with the on load function that calls a function s() which doesn't exist:
    Public Sub Form_Load() Handles Me.Load
    s()
    End Sub


    If your VB.NET Application won't run on Windows 7

    Despite being primarily a web developer, every now and then at my office, I need to create small little Windows Form based applications that perform one or two simple tasks to help out the every day processes of the staff.

    Recently a couple people at our office were upgraded to Windows 7, and have experienced issues with those Visual Studio 2008 based applications, either during installation or running them after installing.

    After some investigation, I stumbled upon the cause of the problem and a solution. Whether it is the machine or the operating system or gremlins sneaking around in this guy's new computer; for some reason, code compiled to work with the Target CPU value "AnyCPU" won't run on this machine.

    To correct the issue, I opened the project settings in Visual Studio and clicked through to the Advanced Compiler Settings:
    Project -> Compile -> Advanced Compile Options

    Change the "Target CPU" field to "x86" and click OK.
    Publish your application and it should install and run on the Windows 7 computer now.


    Windows 7 Visual Studio 2008 Project Settings Target CPU

    Monday, June 28, 2010

    How To Fill a GridView with Custom Objects in an Arraylist using a DataTable

    Usually when I use a GridView, I pull and write to a database table, which is the easiest way to use them. All of the Edit and Delete commands are pretty much prepackaged together with the SqlDataSource control.

    However, I recently found myself building a shopping cart tool that didn't touch a database until the user submits the order. I personally like to write to the database right away in case the client gets disconnected, but in this particular case, I didn't have that pleasure.

    So, I needed to be able to pull an arraylist of objects of type ORDER (a custom class I build) out of the session variable SHOPPINGCART (another custom class I built) and feed them into a gridview for the user to edit quantity, remove items from the cart, etc before checking out.

    I first put together my GridView:
    <asp:GridView
    ID="gvYourCart"
    DataKeyNames="OrderID"
    AutoGenerateColumns="false"
    runat="server">
    <Columns>
    <asp:BoundField
    HeaderText="Quantity"
    DataField="Quantity" />
    <asp:BoundField
    HeaderText="Device Model"
    DataField="Device Model"
    ReadOnly="true" />
    <asp:BoundField
    HeaderText="Rate Plan"
    DataField="Rate Plan"
    ReadOnly="true" />
    <asp:BoundField
    HeaderText="Total One Time Cost"
    DataField="Total One Time Cost"
    ReadOnly="true" />
    <asp:BoundField
    HeaderText="Total Recurring Costs"
    DataField="Total Recurring Costs"
    ReadOnly="true" />
    </Columns>
    </asp:GridView>

    I only want users to be able to edit the Quantity field and remove orders from the cart, so I've made all other columns readonly.

    Now, to start populating my gridview, I'll need to create a DataTable and populate it with the fields that are relavant to what I'll be displaying.
    Private _dt As Data.DataTable
    Public Sub Form_Load() Handles Me.Load
    CType(Master.FindControl("nav_order"), HtmlTableCell).Attributes.Add("class", "nav_highlight")
    _dt = New Data.DataTable()
    _dt.Columns.Add("OrderID")
    _dt.Columns.Add("Quantity")
    _dt.Columns.Add("Product Model")
    _dt.Columns.Add("Total One Time Cost")
    gvYourCart.DataSource = _dt
    If Not IsPostBack Then
    BindData()
    End If
    End Sub

    Public Sub BindData()
    For Each thisOrder As Order In CType(Session("ShoppingCart"), ShoppingCart).Orders
    Dim newRow As Data.DataRow = _dt.NewRow()
    newRow.Item("OrderID") = thisOrder.ID
    newRow.Item("Quantity") = thisOrder.Quantity
    newRow.Item("Product Model") = thisOrder.Product.Name
    newRow.Item("Total One Time Cost") = FormatCurrency(thisOrder.OneTimeCost(), 2)
    _dt.Rows.Add(newRow)
    Next
    gvYourCart.DataBind()
    End Sub

    Because I know that I will need to bind data to my gridview every time I edit or delete from the control, I went ahead and created a BindData function that will pull data from my Shopping Cart in sessions and tie its data to the DataTable.

    In order to edit and delete rows of my GridView, I will need to create 4 new functions (these are usually handled by the UpdateCommand and DeleteCommand of the SqlDataSource, but we'll need to build our own since we're doing things a little more custom than usual.

    Add the following tags to the GridView control:
    AutoGenerateEditButton="true"
    AutoGenerateDeleteButton="true"
    OnRowEditing="EditQty"
    OnRowCancelingEdit="CancelEditQty"
    OnRowUpdating="UpdateEditQty"
    OnRowDeleting="DeleteOrder"


    Now, at this point your code may look nothing like mine, but this should give you a pretty good start.

    The EditQty sub procedure will pretty much always look like this. All we are doing is telling the GridView which row we will be editing. Because we set some columns as ReadOnly, they will not be editable.

    Public Sub EditQty(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs)
    gvYourCart.EditIndex = e.NewEditIndex
    BindData()
    End Sub


    Again, the CancelEditQty sub procedure is pretty standard. We are just letting the gridview know that we don't want to edit any rows by setting the EditIndex to -1.

    Public Sub CancelEditQty()
    gvYourCart.EditIndex = -1
    BindData()
    End Sub


    Because I didn't allow for sorting on my GridView, I know that the shopping cart's order are displayed on the GridView in the same order as they are stored in the shopping cart, so I can afford to make the assumption that the index of the ArrayList in my ShoppingCart object's Orders property matches the e.RowIndex of the GridView, but be careful of how you make your edits.

    Public Sub UpdateEditQty(ByVal sender As Object, ByVal e As GridViewUpdateEventArgs)
    Dim thisRow As GridViewRow = gvYourCart.Rows(e.RowIndex())
    CType(CType(Session("ShoppingCart"), ShoppingCart).Orders(e.RowIndex), Order).Quantity = CType(thisRow.Cells(1).Controls(0), TextBox).Text

    gvYourCart.EditIndex = -1
    BindData()
    End Sub

    Ditto.

    Public Sub DeleteOrder(ByVal sender As Object, ByVal e As GridViewDeleteEventArgs)
    CType(Session("ShoppingCart"), ShoppingCart).Orders.RemoveAt(e.RowIndex())
    BindData()
    End Sub


    And that is it! You should now be able to view the contents of your ShoppingCart or other ArrayList in GridView form, and make easy edits and deletes.


    How To Fill a GridView with Custom Objects from an Arraylist using a DataTable

    Monday, June 14, 2010

    AJAX and URL Rewrite: Sys is undefined Issue

    I created a website on a subfolder of my domain, and later moved it to a subdomain as its own application. Oddly, after I did this, I saw an issue pop up wherein javascript errors were thrown every time I opened a page that:
    Message: Syntax error
    Line: 3
    Char: 1
    Code: 0
    URI: http://(domain)/WebResource.axd?d=3sB1WgLxUgrovkMyz-aqWw4&t=633626442871064790

    ... along with 2 errors for the ScriptResource.axd file and 2 instances of a 'Sys' is undefined error.
    After some research, I found that this is caused by the combination of AJAX and URL Rewrite. I'm not sure if it is specific to GoDaddy hosting, or global. It's strange that it didn't surface until I moved my project. Regardless, I have found a solution.

    The major problem is that my application is not recognizing the WebResource.axd and ScriptResource.axd as files; therefore tying to rewrite their urls using them as keywords.

    My current URL Rewrite structure looks like this:
    <rewrite>
    <rules>
    <rule name="RewriteCheck" stopProcessing="true">
    <match url="^(.+)$" />
    <conditions logicalGrouping="MatchAll">
    <add input="{REQUEST_FILENAME}"
    matchType="IsFile"
    negate="true" />
    <add input="{REQUEST_FILENAME}"
    matchType="IsDirectory"
    negate="true" />
    </conditions>
    <action type="Rewrite" url="UserProfile.aspx?key={R:0}" />
    </rule>
    </rules>
    </rewrite>


    I'm already checking for files and directories, but now I need to check for these .axd files before casting a url into the rewriter. Therefore, I'll use the bounce URLs off a pattern *.axd to negate them from being processed by the Rewrite function.
    <rewrite>
    <rules>
    <rule name="RewriteCheck" stopProcessing="true">
    <match url="^(.+)$" />
    <conditions logicalGrouping="MatchAll">
    <add input="{REQUEST_FILENAME}"
    matchType="IsFile"
    negate="true" />
    <add input="{REQUEST_FILENAME}"
    matchType="IsDirectory"
    negate="true" />
    <add input="{URL}"
    pattern=".*.axd$"
    negate="true" />
    </conditions>
    <action type="Rewrite" url="UserProfile.aspx?key={R:0}" />
    </rule>
    </rules>
    </rewrite>


    I re-ran my application and every worked like a charm!

    Wednesday, June 2, 2010

    Vanity URLs with GoDaddy Hosting using URL Rewrite

    GoDaddy is a very affordable web hosting provider and domain registrar. I often recommend them to most of my clients who don't already have hosting set up. Unfortunately, GoDaddy does not allow you to access the IIS panel directly which sometimes makes a simple task slightly more complex as you have to navigate through their hosting control center, or sometimes entirely unfeasible. However, for the most part, they provide you with everything you would need to host most websites for a nominal fee.

    I've recently had the need to create a portal that used vanity urls for each user profile on the site. For instance, if Aaron, Bob and Carl all have profiles on the portal, their respective portals may be:
    Aaron: digitalplaydoh.com/profile.aspx?id=2
    Bob: digitalplaydoh.com/profile.aspx?id=5
    Carl: digitalplaydoh.com/profile.aspx?id=31

    The client would like users to be able to select a unique ID for their account that can be typed out after the domain that will take users straight to their profile, similar to what you would find on Facebook or MySpace. ie:
    Aaron: digitalplaydoh.com/aaronsmith
    Bob: digitalplaydoh.com/bigbob
    Carl: digitalplaydoh.com/carl


    Microsoft's URL Rewrite module comes preinstalled on GoDaddy accounts with IIS 7.0. Here's where things get a little unfortunate for the GoDaddy developer. While running IIS 7.0, you will be unable to use Front Page Extensions, which means if you're using Visual Studio, you'll need to now connect to the site with the FTP method. Not terrible, but definitely a little slower.

    Once you're running IIS 7.0, we're ready to start using the Microsoft URL Rewrite module. Open your web.config file and go to the <system.webServer> and add the following:
    <system.webServer>
    <rewrite>
    <rules>
    <rule name="RewriteCheck" stopProcessing="true">
    <match url="^(.*)$" />
    <conditions logicalGrouping="MatchAll">
    <add input="{REQUEST_FILENAME}"
    matchType="IsFile"
    negate="true" />
    <add input="{REQUEST_FILENAME}"
    matchType="IsDirectory"
    negate="true" />
    </conditions>
    <action type="Rewrite" url="Profile.aspx?key={R:0}" />
    </rule>
    </rules>
    </rewrite>
    </system.webServer>


    This allows us to find any path that is not a file or directory, and redirect it to Profile.aspx?key=(path). This means I need to now make sure that Profile.aspx can support me passing a "key" request parameter in instead of an "id", which is just a little work in how we pull from the database, but we've otherwise now go the ability to go to http://digitalplaydoh.com/carl and get Carl's profile page.

    Note that you also need to be ready for an incorrect "key". Should I accidently type http://digitalplaydoh.com/calr, you need to be able to catch this as a incorrect keyword and show a proper error page.

    Friday, May 28, 2010

    How To Display HTML Code on a Website

    I used to think that the PRE html tag would let you type anything and show it as it appears in your source, but it seems like all the PRE tag does is allow you to type spaces without the web browser ignoring it.

    Anyways, you can show html code on your page without the browser attempting to render the html object, as shown in the picture below.



    All you have to do is change all of your tags brackets from <> to &lt; and &gt;.
    The letters lt and gt stand for less than and greater than, as in the convention use of the symbols. So, if you wanted to show someone how to make some text bold and some text italic underneath a picture, you could type:
    &lt;div&gt;&lt;img src="selfportrait.jpg" alt="A Picture Of Me By Me!" /&gt;&lt;/div&gt;
    &lt;div&gt;&lt;b&gt;My Self Portrait&lt;/b&gt; - &lt;i&gt;Created By Me&lt;/i&gt;&lt;/div&gt;

    And they would see:
    <div><img src="selfportrait.jpg" alt="A Picture Of Me By Me!" /></div>
    <div><b>My Self Portrait</b> - <i>Created By Me</i></div>


    Another little side note, in order to display &lt; without the browser turning it into a <, you can encode the ampersand the same way we encoded the bracket: &amp;lt;

    How To Access the Data Key When Editing A GridView Row

    Usually, when I create a GridView, I use an ID field that represents a unique ID tied to each row that I can use to update the database, as seen in the picture below.


    However, I recently had a client request that I remove this field as it was confusing their customers. Fair enough. I removed the field, but now I had trouble updating or deleting the database. The field I was formerly using for my WHERE clause is no longer available. Luckily, I've fed the same ID field into the gridview as a Key:

    <asp:GridView
    ID="GridView1"
    AutoGenerateColumns="false"
    CellPadding="3"
    DataKeyNames="orderID"
    AllowSorting="true"
    AutoGenerateSelectButton="true"
    AutoGenerateEditButton="true"
    AutoGenerateDeleteButton="true"
    OnRowEditing="GridView1_RowEditing"
    OnRowUpdating="GridView1_RowUpdating"
    OnRowCancelingEdit="GridView1_RowCancelingEdit"
    runat="server">


    It would seem like common sense to be able to use the GridViewUpdateEventArgs parameter of my GridView1_RowUpdating Sub procedure a la e.Keys("orderID") to get the id of that particular row, but it return nothing. I'm not sure why this function of GridViewUpdateEventArgs exists, but I've never been able to get it to produce a value.

    Exploring it a bit more, I looped through different arrays the GridView would provide and finally found the value using this method:

    GridView1.DataKeys(e.RowIndex).Value

    GridView1.DataKeys will provide a list of all the Keys of the gridview and feeding in the e.RowIndex will indicate that you want the key for the row you are editing.

    Friday, May 21, 2010

    How to pull a value from a Textbox within a CreateUserWizard control

    Just a little quick and dirty note. I've created a CreateUserWizard with several extra controls such as a RadioButtonList, a CheckboxList, a Textbox or two, etc.

    I found myself having trouble in pulling the values from those fields in order to properly configure the new user's profile, until I finally figured this one out.

    With a control called MyCustomTextbox in a CreateUserWizard called CreateUserWizard1, I can pull the value this way:

    CType(CreateUserWizard1.CreateUserStep.ContentTemplateContainer.FindControl("MyCustomTextbox"), TextBox).Text

    Wednesday, May 5, 2010

    How To Sort With a Custom GridView ItemTemplate

    I've been playing around a lot today with the GridView control and wanted to try to use it as a listing tool to show results from a search.

    I would prefer to display the results in a stylized panel rather than the usual spreadsheet format. To accomplish this, I can use the <asp:TemplateField> column object and build any kind of HTML my heart desires:

    <asp:TemplateField>
    <ItemTemplate>
    <div style="background-color: #e4e4e4; color: #303030; padding: 10px;">
    <div>
    <%#Eval("row_image")%>
    </div>
    <div>
    <%#Eval("row_name")%>
    </div>
    <div>
    <%#Eval("row_description")%>
    </div>
    <div>
    <%#Eval("row_priceRange")%>
    </div>
    </div>
    </ItemTemplate>
    </asp:TemplateField>


    Now, I want to use the GridView control's Sorting feature that is usually handled by the HeaderText. I want to allow users to sort by Name, Description and Price Range. I can create a a column for each of these fields that will also create HeaderText that I can then use for the SortExpression value:
    <asp:TemplateField HeaderText="Name" SortExpression="row_name" />
    <asp:TemplateField HeaderText="Description" SortExpression="row_description" />
    <asp:TemplateField HeaderText="Price Range" SortExpression="row_priceRange" />

    I used the TemplateField control rather than the BoundField so that I wouldn't actually populate any data into the field. It's just a header and a blank cell with the width of the HeaderText. This will create a lot of empty space to the right of my GridView which I don't want, plus the clickable Headers are way to the right of the GridView itself.

    A little bit of CSS easily fixed the issue. I'll set my CssClass of the GridView to CssClass="gv_list" and add the following css structure:
    .gv_list th {
    float: left;
    }

    Now, I've got three links at the top of my GridView that I can use for sorting the content either Ascendingly or Descendingly. Just to make sure all my site visitors understand what the links are for, I'll add some HeaderText to my first column (with all the divs) HeaderText="Sort By" and we are golden.


    Getting rid of the top and bottom border on the GridView in FireFox

    You'll soon find that I'm not one of those developers who praises FireFox and bashes Internet Explorer. I've always developed for IE since it has long been the most used browser; but within recent history, the red fox has snuck up and become the most used browser on the market.

    By default, FireFox adds a border at the top and bottom of GridView cells.


    Try all the CSS you want, but you won't be able to get rid of these cursed little lines. It is actually a setting in the GridView control itself. All you need to do is set GridLines="None" and the lines disappear.

    Just that easy!