Formatting a phone number in ASP.NET data bound controls

As part of my ongoing “stop coding like it’s 1999″ regime, I managed to think my way out of some code in the following scenario:

My business object returns a phone number, but it happens to be a raw number, i.e. there’s no formatting: (416) 967-1111 comes back as 4169671111. I’ve got a repeater control in ASP.NET, and I want to pretty it up.

In the past, I’d:

  1. Code a new property into the business object to give me a formatted string.
  2. Add an ItemDataBound event handler to the repeater, which calls FindControl and fills in the value all pretty-like.
  3. Ignore the issue and hope nobody notices.

The new and improved Luke does this in his <ItemTemplate> node:

<%# String.Format(
   ”{0:(###) ###-####},
   Convert.ToInt64(
      DataBinder.Eval(Container.DataItem, “PhoneNumber”)))
%>

Not the prettiest thing in the world, but (after some thinking) the easiest, and it actually puts the presentation details at the right layer.

If I’m not careful, I might actually become productive.

Pop quiz: is there a cleaner way to do this?

This entry was posted in .Net. Bookmark the permalink.

18 Responses to Formatting a phone number in ASP.NET data bound controls

  1. harsha says:

    rice one..it would rather do all my formating on client side…

  2. harsha says:

    What i really meant was that I would my formating using javascript/vbscript …:)

  3. Luke says:

    Yeah, but the idea here is to do less work, not more. Do you have a URL with an example of formatting a phone number via javascript? It sounds like overkill to me…

    Luke

  4. Kelly says:

    Luke, you are the man. I’ve been trying to use formatting in item templates with the old VBScript formatting functions and sometimes they just don’t work. It never occurred to me that I could use the String.Format Static method in the HTML. Thanks

  5. Luke says:

    Funny you should mention that today, Kelly, I just did a weird bit of data binding this morning that reminded me of this post! I should get off my butt and write more about this stuff, it’s the only way I’ll remember it…

  6. jeaux says:

    DataBinder.Eval(Container.DataItem, “Phone_Number”,”{0:(###) ###-####}”)

  7. Jason says:

    Jeaux, that won\’t work – the var is defined as a string, so the formatting is pretty much ignored, as far as I can tell – you need to convert it to a number first.  I had a lovely example page made up, but WP doesn\’t want to let me add it to the comments, so you\’ll just have to trust me, or try it for yourself.

  8. Victor Escobar says:

    When I used your code, I got the following error:

    Object cannot be cast from DBNull to other types.
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.InvalidCastException: Object cannot be cast from DBNull to other types.

    Source Error:

    Line 40: HeaderText=”Phone Number” SortExpression=”strPhoneNumber”>
    Line 41:
    Line 42:
    Line 43:
    Line 44:

    Source File: C:\inetpub\XXX\YYY\ZZZ.aspx Line: 42

    Stack Trace:

    [InvalidCastException: Object cannot be cast from DBNull to other types.]
    System.DBNull.System.IConvertible.ToInt64(IFormatProvider provider) +54
    System.Convert.ToInt64(Object value) +25
    ASP.admin_admin_evaluator_aspx.__DataBind__control16(Object sender, EventArgs e) in C:\inetpub\XXX\YYY\ZZZ.aspx:42
    System.Web.UI.Control.OnDataBinding(EventArgs e) +99
    System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) +206
    System.Web.UI.Control.DataBind() +12
    System.Web.UI.Control.DataBindChildren() +216
    System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) +216
    System.Web.UI.Control.DataBind() +12
    System.Web.UI.Control.DataBindChildren() +216
    System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) +216
    System.Web.UI.Control.DataBind() +12
    System.Web.UI.WebControls.GridView.CreateRow(Int32 rowIndex, Int32 dataSourceIndex, DataControlRowType rowType, DataControlRowState rowState, Boolean dataBind, Object dataItem, DataControlField[] fields, TableRowCollection rows, PagedDataSource pagedDataSource) +221
    System.Web.UI.WebControls.GridView.CreateChildControls(IEnumerable dataSource, Boolean dataBinding) +3004
    System.Web.UI.WebControls.CompositeDataBoundControl.PerformDataBinding(IEnumerable data) +59
    System.Web.UI.WebControls.GridView.PerformDataBinding(IEnumerable data) +11
    System.Web.UI.WebControls.DataBoundControl.OnDataSourceViewSelectCallback(IEnumerable data) +111
    System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback) +29
    System.Web.UI.WebControls.DataBoundControl.PerformSelect() +149
    System.Web.UI.WebControls.BaseDataBoundControl.DataBind() +70
    System.Web.UI.WebControls.GridView.DataBind() +4
    System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound() +82
    System.Web.UI.WebControls.CompositeDataBoundControl.CreateChildControls() +69
    System.Web.UI.Control.EnsureChildControls() +87
    System.Web.UI.Control.PreRenderRecursiveInternal() +41
    System.Web.UI.Control.PreRenderRecursiveInternal() +161
    System.Web.UI.Control.PreRenderRecursiveInternal() +161
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1360

    ——————————————————————————–
    Version Information: Microsoft .NET Framework Version:2.0.50727.42; ASP.NET Version:2.0.50727.210

  9. Jason says:

    Victor, can you email me the source file so I can see what else is going on? I’ll try to put an update on demos tonight…

  10. Thanks for this – I have been Googling for the last 24 hours for something like this. I did find your syntax was off just a tad – this is what worked for me:

  11. String.Format(“{0:(###) ###-####}”, Convert.ToInt64(DataBinder.Eval(Container.DataItem,”homephone”)))

  12. Cetin Basoz says:

    Pardon me but telephone numbers are not made up of digits all the time. Wouldn’t something like this cause a parsing error?

    800VERIZON

    or (formatted):

    +1 (555) 1234567 [1234]
    +1 555 1234567 – 1234
    +1 555 123 45 67 – 1234
    00 1 (555) 1234567
    444 0 MSI

    etc.

    Maybe storing it as end users wrote is the way. People are accustomed to type in such data in the format they are familiar most.
    To me it’s neither the job of data layer nor presentation. Humans can easily interpret those numbers.

  13. Good info. But I agree with the Harsh- I prefer the client side to do all the ugly work…

  14. Great post
    I agree with Cetin Basoz.
    I believe that storing it as the users do- is the way.

  15. Jeremy says:

    Actually, it would be best to parse the digits out when accepting the data using regex. Storing various formats of the same style is a nightmare to maintain. Taking a we’ll-just-deal-with-whatever-they-input approach will eventually cause a lot of problems (especially on the security side).

  16. Haniel Croitoru says:

    Hi all,

    This post is very useful. One additional question I have on this is, how do I deal with the situation where the phone number may be blank? The browser throws an exception at that point.

  17. Andy says:

    public static string FormatPhoneNumber(string pNum)
    {
    pNum = RemoveNonIntegers(pNum);
    if (pNum.Length == 10)
    return String.Format(“{0:(###) ###-####}”, Int64.Parse(pNum));
    else if (pNum.Length == 7)
    return String.Format(“{0:###-####}”, Int64.Parse(pNum));
    else return “Invalid string format”;
    }

  18. Jason says:

    Haniel, there’s not a lot of error handling (i.e. none) in this technique – a helper function like Andy provided would be a better approach here.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>