ASP.NET MVC Gravatar HtmlHelper

ASP.NET MVC, Code 1 Comment

Here is a quick little URL Helper extension method to add Gravatar images/photos/avatars to your page:

public static string GravatarUrl(this UrlHelper url, string email, int size)
{
    string imageUrl = ConfigurationManager.AppSettings["DefaultGravatar"];
    if (imageUrl.StartsWith("~/"))
    {
        imageUrl = url.Absolute(imageUrl);
    }

    if (string.IsNullOrEmpty(email))
    {
        return imageUrl;
    }

    string md5 = email.ToLowerInvariant().MD5();
    return string.Format(
        "http://www.gravatar.com/avatar/{0}.jpg?d={1}&s={2}&r=g",
        md5.ToLowerInvariant(),
        url.Encode(imageUrl),
        size);
}

public static string GravatarUrl(this UrlHelper url, string email)
{
    return url.GravatarUrl(email, 32);
}

It uses another custom URL Helper extension method Absolute to generate an absolute URL to a default image (based on an application relative url).

The Absolute extension method is similar to the ActionAbsolute method I posted earlier:

public static string Absolute(this UrlHelper url, string contentUrl)
{
    return new Uri(GetBaseUrl(url), url.Content(contentUrl))
        .AbsoluteUri;
}

And it also used the MD5 extension method from yesterdays post.

Getting an absolute URL from ASP.NET Webforms

ASP.NET No Comments

Related to the post Getting an absolute URL from ASP.NET MVC here is the corresponding ASP.NET Webforms version (not as extension methods):

public static Uri GetBaseUrl(HttpRequest request)
{
    Uri contextUri = new Uri(request.Url, request.RawUrl);
    UriBuilder realmUri = new UriBuilder(contextUri) { Path = request.ApplicationPath, Query = null, Fragment = null };
    return realmUri.Uri;
}

public static string GetAbsoluteUrl(HttpRequest request, string relativeUrl)
{
    return new Uri(GetBaseUrl(request), VirtualPathUtility.ToAbsolute(relativeUrl)).AbsoluteUri;
}

Getting an absolute URL from ASP.NET MVC

ASP.NET MVC 4 Comments

I have been in situations where I need to generate an absolute URL to a specific action in an ASP.NET MVC application. The main problem mostly lies in getting the “domain” part of the URL. The only way to do this is to examine the request URL. I came across a very nice method of doing this during an encounter with the dotnetopenid

public static Uri GetBaseUrl(this UrlHelper url)
{
    Uri contextUri = new Uri(url.RequestContext.HttpContext.Request.Url, url.RequestContext.HttpContext.Request.RawUrl);
    UriBuilder realmUri = new UriBuilder(contextUri) { Path = url.RequestContext.HttpContext.Request.ApplicationPath, Query = null, Fragment = null };
    return realmUri.Uri;
}

public static string ActionAbsolute(this UrlHelper url, string actionName, string controllerName)
{
    return new Uri(GetBaseUrl(url), url.Action(actionName, controllerName)).AbsoluteUri;
}

jQuery and AJAX Tooltips

ASP.NET MVC, jQuery 2 Comments

So the day has dawned, very symbolic that this day happens to be the first of a new year… enough of that. The day has finally come where I post a JavaScript entry! Who would have thought that???

Over the last couple of months I have had a very passionate relationship with a new hottie I discovered. She is named jQuery and OMG can she do tricks… OK, stop this talk right now :)

Basically I have had my head in AJAX for ASP.NET doing what others before already realized probably wasn’t the best approach. Finally I got around to have a look at jQuery and I must admit that (especially for my ASP.NET MVC project(s)) I haven’t looked back!!!

Today I had a little feature I wanted to solve with some AJAX:

I have a list of objects displayed in a certain view. One property on these objects is calculated and involved some semi-heavy database and calculation stuff and therefore requires both time and system resources to get. This value is not in particular important to the current view, but is a nice-to-have information. This means that the value as such does not need to appear in the view after rendering. I therefore figured it could be nice to have in a dynamic tooltip, i.e. “on tooltip hover, calculate/retrieve the value and display it as a tooltip”.

Having used other of Jörn Zafferer jQuery plug-in’s previously (with great success) I turned my attention to his tooltip plugin.

Having read the documentation it is apparent that, while you can specify a callback function (namely the “bodyHandler” property) to determine which “value” to display in the tooltip, there is an issue with this: it is synchronous! And by definition AJAX is asynchronous. The problem here is that if you do a $.get() call you the return value of the bodyHandler callback is “out of scope”, since it is first available once the AJAX call is completed, i.e.:

$(".tooltip-element").tooltip({
    bodyHandler: function() {
        $.get("/MyController/MyAction", { id : "myid" }, function(data) { /* do what with "data"? */; }, "html");
    },
    showURL: false
});

My solution to this was the following:

$(".tooltip-element").tooltip({
    bodyHandler: function() {
        var result = $("<span/>").html("some loading indicator");
        $.get("/MyController/MyAction", { id: "myid" }, function(data) { result.html(data); }, "html");
        return result;
    },
    showURL: false
});

I think that is pretty nifty! Of course the “some loading indicator” can be tweaked (e.g. use a AJAX load indicator). And this is of course not specific to ASP.NET MVC!

UPDATE:

There is a problem with this approach! The jQuery tooltip plugin used seems to invoke the bodyHandler callback directly “on mouse over”, ie. not after the delay. This means that although the tooltip displays nicely after the specified delay, the Ajax call was performed at T=0. What this effectively means is that if you eg. have a table where all values in column 1 have this Ajax-tooltip-thingy. If you then move the mouse in over a couple of the values each time you the cursor is over the value an Ajax call is executed. Not so good unless you want to utilize all resources in your server :)

Back to the drawing board…

ASP.NET MVC HtmlHelper methods and CSS class

ASP.NET MVC 4 Comments

If you in ASP.NET MVC use a Html helper method to render out e.g. an input box:

<% = Html.TextBox("name")  %>

Sometimes you might need to add an CSS class attribute to your input box (this should be a fairly standard thing). For this there exist overload methods that takes a “htmlAttributes” parameter of type object. Now my experience with this is somewhat similar to Ayende Rahien experience – although I have not begun banging my head against the wall out of frustration. This is not a rant, I love ASP.NET MVC, I just had an experience with something simple that was hard to figure out because of some of the design decisions – not that they are bad, they can just be confusing – especially with the lack of documentation at the current stage (yes, I know it is just a beta). So if you try this:

<% = Html.TextBox("name", null, new{ class = "required"})  %>

You will (of course) get a compiler error, since “class” is a keyword and cannot be used like this. So how do you specify the class? Well, like this:

<% = Html.TextBox("name", null, new{ @class = "required"})  %>

Just for future reference :)

Cool upcoming .NET stuff from Microsoft

.NET General, ASP.NET 1 Comment

Silverlight 2.0

Version 2.0 of the ubercool Silverlight, Microsoft’ pendant to Adobe Flash, is drawing nigh. Currently available as beta 2, release in june ‘08. Silverlight 2.0 allows embedded code client-side, by some magic, that does not even require having the .NET framework installed on the client.

ASP.NET MVC Framework

Quoting the ASP.NET MVC page:

ASP.NET MVC enables you to build Model View Controller (MVC) applications by using the ASP.NET framework. ASP.NET MVC is an alternative, not a replacement, for ASP.NET Web Forms that offers the following benefits:

  • Clear separation of concerns
  • Testability – support for Test-Driven Development
  • Fine-grained control over HTML and JavaScript
  • Intuitive URLs

References: Official page, Scott Guthrie MVC Preview 5 Release post

Zermatt

Quoting Zermatt home page:

Zermatt is a framework for implementing claims-based identity in your applications. By using it, you’ll more easily reap the benefits of the claims-based identity model described in this paper.

References: Official page, Vittorio Bertocci blog, Keith Brown blog

Velocity

Quoting Velocity Blog

(…) a distributed caching product to provide the .NET application platform support for developing highly performant, scalable, and highly available applications.

References: Velocity blog

Oslo

Quoting the official Oslo page:

”Oslo” is the codename for Microsoft’s forthcoming modeling platform. Modeling is used across a wide range of domains and allows more people to participate in application design and allows developers to write applications at a much higher level of abstraction. “Oslo” consists of:

  • A tool that helps people define and interact with models in a rich and visual manner
  • A language that helps people create and use textual domain-specific languages and data models
  • A relational repository that makes models available to both tools and platform components

References: Official page, Douglas Purdy – "What is Oslo?", Don Box blog, Various MS SOA articles (incl. non Oslo stuff)

Abuse of FormsAuthentication.HashPasswordForStoringInConfigFile() method?

.NET General, ASP.NET 3 Comments

I can’t help but get a annoyingly creepy feeling whenever I see people using FormsAuthentication.HashPasswordForStoringInConfigFile() to generate a hash cipher for a given value (for example here). On the other hand I can’t really decide wether I think it is the method which has a bad name/should be "located" somewhere else or it is the "abuse" of it as it is today.

If we look at the actual implementation of HashPasswordForStoringInConfigFile using Reflector:

public static string HashPasswordForStoringInConfigFile(string password, string passwordFormat)
{
    HashAlgorithm algorithm;
    if (password == null)
    {
        throw new ArgumentNullException("password");
    }
    if (passwordFormat == null)
    {
        throw new ArgumentNullException("passwordFormat");
    }
    if (StringUtil.EqualsIgnoreCase(passwordFormat, "sha1"))
    {
        algorithm = SHA1.Create();
    }
    else
    {
        if (!StringUtil.EqualsIgnoreCase(passwordFormat, "md5"))
        {
            throw new ArgumentException(SR.GetString("InvalidArgumentValue", new object[] { "passwordFormat" }));
        }
        algorithm = MD5.Create();
    }
    return MachineKeySection.ByteArrayToHexString(algorithm.ComputeHash(Encoding.UTF8.GetBytes(password)), 0);
}

The net result of this of course is that you do get the MD5/SHA1 hash of the password or value.

However the method name is HashPasswordForStoringInConfigFile, i.e. the name suggests it is for hashing passwords and further more it is a method of a class called FormsAuthentication… see a pattern!? The name does not suggest it is a generic MD5 method (although the implementation shows it is that).

IMHO using HashPasswordForStoringInConfigFile as a generic MD5 calculation method does nothing but make code less readable and hence harder to maintain. The very, very least a developer can do is to comment the code, but we all know when that’ll happen…

Look at the alternative:

public static string GetMD5(string value)
{
    MD5 algorithm = MD5.Create();
    byte[] data = algorithm.ComputeHash(Encoding.UTF8.GetBytes(value));
    string md5 = "";
    for (int i = 0; i < data.Length; i++)
    {
        md5 += data[i].ToString("x2").ToLowerInvariant();
    }
    return md5;
}

The ONLY problem with not doing this stuff yourself is the conversion from a string and back to a string…

Yes, this might be a little slower due to the string stuff, but you can always "inherit" ;) the MachineKeySection.ByteArrayToHexString method.

The point is that using FormsAuthentication.HashPasswordForStoringInConfigFile to calculate all MD5/SHA-1 hash values just because the implementation happens to support this seems wrong. Writing this I think I actually blame Microsoft the most for not providing this method somewhere else and named more appropriately.

That was just a little rant…

Drag and Drop Control Extenders

.NET General, ASP.NET AJAX, Code No Comments

After reading Jeff Prosise’s MSDN magazine article (January 2008 edition) on Drag and Drop with ASP.NET AJAX (actually something he blogged about back in March 2007) I think the time has come to put my $0.02 on the issue. Actually it is not my $0.02 but merely a "formalization" of Jeff’s work.

I took his drag and drop implementation and created two control extenders, namely a Drag Source extender and a Drop Target extender. I added functionality to allow specifying the key/value of a drag object (i.e. which object you are actually dragging) and a key/value on the drop target (i.e. knowing where you drop the object, e.g. if a drop target is inside a repeater).

Usage is extremely simple. As always simply point the DragSourceExtender and/or DropTargetExtender to an ASP.NET Server Control (this is the "limitation", it must be a server side control), set the DragType, DropType, DragValue and DropValue as required and create a callback method in the OnClientDrop "event handler"/callback on the drop target.

The callback signature is:

/// <summary>
/// Client-side drop event handler/callback method signature
/// </summary>
/// <param name="sender" type="Veggerby.DropTargetBehavior" domElement="false">
/// The DOM element the drop is associated with
/// </param>
/// <param name="e" type="Veggerby.DropEventArgs" domElement="false">
/// EventArgs for the drop operation, includes references to DragSource and DropTarget
/// </param>
function OnClientDrop(sender, e)
{
}

Future enhancements could/would include allowing a service call on a successful drop, however currently this can be (easily) achieved manually in an OnClientDrop callback.

Download the source code here.

Sign-up and Login in One Step Membership Provider

ASP.NET, Code No Comments

Why has it got to be so hard? Why do you always have to go through a user creation wizard to create an account? Why just not create it as you login like they do on LibraryThing for example?

Well, there is of course always two sides to a coin. The obvious reason is: spam. However all that is needed is an username to "aggregate" your info, then this does not really matter.

So here is a very simple solution to this:

Create a custom MembershipProvider and in the ValidateUser() method first check if the user exists. If not then create the user and then validate him/her. There is of course the requirement that RequiresQuestionAndAnswer and RequiresUniqueEmail must be false.

One way of doing this is to refer a standard membership provider and add some logic to the ValidateUser():

public override bool ValidateUser(string username, string password)
{
    if (GetUser(username, false) == null)
    {
        MembershipCreateStatus status = MembershipCreateStatus.Success;
        MembershipUser user = CreateUser(username, password, null, null, null, true, null, out status);
        if (status != MembershipCreateStatus.Success)
        {
            throw new ProviderException(string.Format("Could not automatically create user: {0}", status));
        }
    }
    return MembershipProvider.ValidateUser(username, password);
}

Download the EasyRegisterMembershipProvider here.

To use this, download, compile and use it in Web.config:

<membership defaultProvider="SignUpProvider">
<providers>
  <clear/>
  <add name="SignUpMembershipProvider" type="Veggerby.Utility.EasySignUpMembershipProvider, Veggerby.Utility" providerName="SqlMembershipProvider"/>
  <add name="SqlMembershipProvider" …/>
</providers>
</membership>

Export GridView to Excel

.NET General, ASP.NET 5 Comments

In Scott Guthrie’s August 30th Links I saw a link to Matt Berseth’s blog about exporting a GridView to Excel.

I have used a method similar to this earlier and apart from it being very easily developed, I have found a very, very annoying issue with this method.

The first thing is you need to make sure the output is localized (in regards to formatting), especially for floating point values and dates (but as I’ll explain, this really is not enough).

What I actually found was that it was/is a pretty tricky thing to accomplish. Normally you would of course just set the Culture in Web.config, in the <%@Page %> section or imperatively on the current thread. For my Windows is using the Danish regional settings, which means that fx. a date is formatted as dd/mm/yyyy, however at the company where I work (we’re global) we have a standard date format (yyyy-mm-dd) which is being set by group policy.

What ASP.NET does when using the Culture, it uses the default settings for the specified language(s) in the request header. This means for me it would specify “da” as language in the browser. This will make ASP.NET set the “da-DK” Culture and format numbers based on the standard danish settings for numbers, dates, etc. Which means that if I make a request to this kind of Excel sheet containing a localized date it will be formatted “dd/mm/yyyy” which will cause Excel to misinterpret it since it expects my date formats to be yyyy-mm-dd.

The above perhaps sound a but hypothetical, but consider this: I have set my language to english in the browser (since I don’t want fx. Windows Update to send me the danish updates to my english OS – which is would otherwise do). So with my language to “en-us” in the browser, I open the Excel sheet using Matt’s method and it will/should format the HTML table output based on the “en-US” culture, however Excel will try to interpret this using my Windows Regional Settings, which is danish. What a mess!!!

In this case when running Matt’s example I get this in my browser:

Browser layout of Matt Berseth Export GridView to Excel

and this in Excel:

Excel version of Matt Berseth Export GridView to Excel

The problem is here that in Danish numerical layout the decimal symbol is , (comma) and the thousand separator is . (dot) – the complete opposite of en-US. This causes Excel to interpret the UnitPrice in Matt’s example as a number with a thousands separator and not a decimal symbol (even though it is displayed with 4 digits after the decimal/thousand separator). So we get UnitPrice’s of 140000, 98000, 348000, etc. (thousand separators left out on purpose :) ) instead of 14, 9.8, 34.8, etc. (here dot is decimal symbol). Even worse is it for Discount, since a Excel will not interpret a number with 0 in front of the thousand separator as a valid number so all the 0 (zeros) in that column are interpreted as numerical zeros, but 0.15 is not interpreted as a number and is left as a “text” and thereby unusable for use in formulas.

If Matt has included dates in this example it would be even worse!

So bottom line is: this is a very simple method and can be very usefull (especially if you have only text values), but if you need to make sure data is consistent, it can be a big pain since it relies on Excel interpreting the HTML output (strings) which is/can be formatted in a number of different ways.

This is not just theoretical, I have experienced these issues in real-life on a real project. If consistent data is needed it would probably require a native format for the export, such as the one used by Veggerby.Excel. That was the lesson I learned from this :)

Icons by N.Design Studio. Designed By Ben Swift. Powered by WordPress, Search Optimization and Free WordPress Themes
Entries RSS Comments RSS Log in