While learning rails I came across a very cool helper method called distance_of_time_in_words. You’ve probably seen this method in action if you’ve used Twitter – no guessing about time zones and as a user I think it’s a nice touch. So on to the port itself…
The Good
C# is automatically faster because everyone knows Ruby is slow and that rails can’t scale.
Seriously though, the port to C# uses resource files so internationalization is handled by simply adding a translated resource file to your project.
The Bad
C# doesn’t have the concept of static extension methods. To me DateTime.DistanceOfTimeInWords would be much nicer than DateHelper.DistanceOfTimeInWords.
Range support in the language is hokey at best. No ranges in switch statements. bleh.
The Ugly
The code! If you compare the C# version to the Ruby version it’s a little ahhhhhhhhhhh… inelegant? The Ruby version weighs in at 28 lines of readable code. The C# version is a b-e-a-s-t with 55 lines of code including 2 helper methods. I’m open to any suggestions in making the C# code shorter or more readable.
The Rest
The method time_ago_in_words has also been ported. Altogether the helper code is 74 lines – also included is over 250 lines of test code. All examples listed on the Rails page were also included in the test.
You can grab the code here or at the subversion repository http://svn.gaskell.org/helpers
]]>jQuery is also really easy to extend – I wrote a couple of extensions that would be usable throughout an application. Here’s the extension I wrote to produce the ubiquitous yellow fade effect:
(function($) { $.fn.yellowFade = function() { return this.css({backgroundColor: "#ffffcc"}) .animate({backgroundColor: "#ffffff"}, 1500, "linear"); } })(jQuery);
Calling this method flows with the rest of jQuery style chaining of methods:
function(data) { $("div#basket").html(data).yellowFade(); });
This one liner is a callback from our http post to the /Cart/AddProduct. The data parameter contains the response from the server. $("div#basket") is getting the container div from our shopping cart. Then we replace the html within the shopping cart div with the response from the server and follow it up with a yellow fade to provide user feedback.
]]>I was checking out Hanselman’s Ajax example (the truly lazy can download the code here) and I was pretty bummed when I disabled javascript and saw this:
Oops. That’s probably not what the user expected. Maybe there’s some way to get the AjaxHelper to save us but none of the 10 overloads for the ActionLink or Form methods stood out to me. Until I get around to really learning jQuery, I’ll stick with writing Ajax by hand. This allows me to request different urls based on whether or not javascript is enabled. And writing your own javascript really isn’t that hard – go grab a good book
.
13 public ActionResult Index()
14 {
15 ViewData.Model = Product.Products;
16 return View(“Index”);
17 }
18
19 public ActionResult AddProductToCart(string productID, int quantity)
20 {
21 CartController cartController = new CartController();
22 cartController.AddProduct(productID, quantity);
23 return Index();
24 }
25
26 public ActionResult RateProduct(string productID, string rating)
27 {
28 RatingController ratingController = new RatingController();
29 ratingController.RateProduct(productID, rating);
30 return Index();
31 }
28 public ActionResult DisplayCart()
29 {
30 Cart cart = GetCart();
31 return View(“Cart”, cart);
32 }
33
34 public ActionResult AddProduct(string productID, int quantity)
35 {
36 Cart cart = GetCart();
37 Product product = Product.Products.Find(s => s.ID == productID);
38 cart.AddProduct(product, quantity);
39 SetCart(cart);
40 return View(“Cart”, cart);
41 }
22 private Rating GetRatings()
23 {
24 Rating rating = System.Web.HttpContext.Current.Session["Rating"] as Rating;
25 if (rating == null)
26 {
27 rating = new Rating();
28 }
29 return rating;
30 }
31
32 private void SetRating(Rating rating)
33 {
34 System.Web.HttpContext.Current.Session["Rating"] = rating;
35 }
This example gets a list of all topics that digg offers. The code is pretty simple:
// Create the web request, change the appkey to for your applications
HttpWebRequest request = WebRequest.Create("http://services.digg.com/topics?appkey=http%3A%2F%2Fgaskell.org") as HttpWebRequest;
// won't get a response from digg if UserAgent is not set
request.UserAgent = ".net";
// Get response
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
DataSet ds = new DataSet();
ds.ReadXml(reader);
this.topicsGridView.DataSource = ds.Tables[1];
this.topicsGridView.DataBind();
}
]]>To get things started here’s a live demo of the digg style paging in asp.net project I created.
]]>About the algorithm (from Stranger Studios):
- The pagination object has a “previous” and “next” button which takes the user to the next page. The previous button is disabled on the first page. Similarly, the next button is disabled on the last page.
- The pagination object will always display links to the first two pages and the last two pages of the set.
- The pagination object will always display links to the first x (adjacents in the code) pages before and after the current page.
- The pagination object will only show at most 5+2x links (first two + prior x + current page + next x + last two). All links not shown will be replaced by …
A little preview:
You can download the project here. I didn’t spend a ton of time testing this code, please leave any bug reports in the comments – Thanks!
Update: Changed the code a bit – paging is now handled via query string instead of posting back. Not a huge deal but the code is easier to read.
]]>Here’s the basic tag:
<uc1:DiggItButton ID="DiggItButton"
runat="server"
Url="http://gaskell.org"
Title="Test title"
Body="Test body" />
You don’t need to set the Url, Title and Body properties in the tag, they are also available as public properties in the codebehind. The only property that is required to be set is the Url property – if you pass in the Title and/or Body, digg will pre-populate those fields. Digg also asks that you url encode your strings and this control handles that for you. Check out the code and sample page here.
]]>
this.Form.DefaultButton = this.YOUR_DEFAULT_BUTTON.UniqueID;
]]>To format DateTime values, you might expect to use a tag like this:
<asp:BoundField
DataField="BeginDate"
DataFormatString="{0:d}"
HeaderText="Begin Date" />
and have a result like this:
10/10/2004
but instead you get a result like this:
10/10/2004 12:00:00 AM
Here’s the fix – add HtmlEncode=”false” to your BoundField tag:
<asp:BoundField
DataField="BeginDate"
HtmlEncode="false"
DataFormatString="{0:d}"
HeaderText="Begin Date" />
The same idea applies to formatting currency, I’m assuming other types of data formatting as well. Here’s Microsoft’s explanation.
Technorati Tags: asp.net, formatting datetime, formatting currency, DetailsView, GridView
]]>