mo.notono.us

Tuesday, August 24, 2010

iPad Mockups To Go

After using the heck out of Peldi’s (here and here) and Simon Herd’s (here) original templates for Balsamiq iPad mockups, I decided to give back to the community by creating some templates that I found were missing:

The iPad Portrait and iPad Landscape templates are 1:1 scale iPad mockups, with an inner frame with 1024x768 resolution.  I assembled the frame of the iPad piecemeal, so as to leave a “hole” in the middle, for your content to shine through.  This is something I sorely missed with Peldi’s templates, forcing me to do far too much work in Paint.Net, manipulating my images to fit his frame exactly.

Complementing these is my iPad Keyboards template.  If you’re already using one of the above templates, this one isn’t necessary, but if you want to use Peldi’s templates, my template will come in handy.  It's simply the iPad keyboard as Simon Herd originally created it, but in 4 different resolutions, with minor corrections:


Enjoy.

Labels: , , , ,

Tuesday, August 17, 2010

The Squrl Lives!

squrlI gave up on my homegrown url-shortening exercise, squrl.us, about a year and a half ago – it started as an experiment in MVC, which I tried to port to server side js, but lack of time and interest got the better of it.  So I shut it down.

Now, thanks to bit.ly Pro, squrl.us is back!  Just too bad I can’t get the cool logo Sean made for me up on the site… :-(

Labels: , , ,

Tuesday, August 10, 2010

XElement, XAttribute and Explicit Conversion Operators

When we (my team at AIS) some xml parsing for the Rolling Stone project, we had to convert element and attribute values to ints and dates, etc. We ran into the problem that sometimes these elements and attributes didn’t exist – so using myXElement.Attribute(myAttribute).Value in a TryParse() would fail with a NullReferenceException, since Value couldn’t be called on a non-existent attribute.

Classic case for an Extension method – which is what I created:

public static T GetAttributeValueOrDefault(this XElement element, XName attributeName, T defaultValue) where T : struct
{
	//First check that the attribute is present
	XAttribute attribute = element.Attribute(attributeName);
	if (attribute == null || attribute.Value == null || attribute.Value == "null")
	{
		return defaultValue;
	}
	//...else attempt conversion
	return attribute.Value.ConvertOrDefault(defaultValue);
}

…except that we were all WRONG: http://www.hanselman.com/blog/ImprovingLINQCodeSmellWithExplicitAndImplicitConversionOperators.aspx

It turns out XAttribute has a series of explicit conversion operators, as does XElement:

Reflector reveals the following for XAttribute (XElement also has the same operators)

public class XAttribute : XObject
{
…

    // Methods
…
    [CLSCompliant(false)]
    public static explicit operator DateTime?(XAttribute attribute);
    [CLSCompliant(false)]
    public static explicit operator bool(XAttribute attribute);
    [CLSCompliant(false)]
    public static explicit operator Guid(XAttribute attribute);
    [CLSCompliant(false)]
    public static explicit operator bool?(XAttribute attribute);
    [CLSCompliant(false)]
    public static explicit operator int(XAttribute attribute);
    [CLSCompliant(false)]
    public static explicit operator Guid?(XAttribute attribute);
    [CLSCompliant(false)]
    public static explicit operator int?(XAttribute attribute);
…
    //etc, etc, etc – umpteen more
…

The implementation of the int? version looks like this;

[CLSCompliant(false)]
public static explicit operator int?(XAttribute attribute)
{
    if (attribute == null)
    {
        return null;
    }
    return new int?(XmlConvert.ToInt32(attribute.value));
}

So to get the value of an XElement/XAttribute, simply cast it to the type you want – make it the nullable variety if you aren’t sure that the attribute/element is present, the explicit conversion operator will check and convert the value for you, then check for null in your code…

Live and learn.

PS!  How are you expected to discover this, without reading the source-code (or Scott’s blog)?

 

  

Labels: , , ,

Monday, August 09, 2010

Dear Microsoft: Embrace JavaScript Already

It’s 2010:JavaScript is 14 years old, and you’ve officially supported “JScript” for the past 13 years.  Yet today, I have to open my JavaScript file in the FREE, OPENSOURCE, NotePad++ to find a missing closing } deep in my JavaScript file, because your latest premium Visual Studio IDE still can’t properly parse the language.

I appreciate the efforts you’ve gone to with improved intellisense in VS2010, but that is far from enough.  Why do we still need macros or plugins for elementary functionality such as function outlining, a document hierarchy tree, bracket matching and other validation?

As long as there is an internet driven by HTML, there will be JavaScript right beside it.  Embrace it already.

Labels: , , , ,

Thursday, August 05, 2010

Seadragon.com is now Zoom.it

Microsoft Live Labs recently rebranded their SeaDragon public Deep Zoom service ‘Zoom It’ and put it at http://zoom.it

They now have an API for Silverlight, .NET and JavaScript, allowing you to submit the url of your image to deep zoom, returning the url for your Deep Zoom Image (DZI). Or, for the non-programmatic approach, you can simply submit your url through the browser at http://zoom.it (the same way you could previoously through seadragon.com).

Completed DZIs are given a very short, incremental url, e.g. http://zoom.it/10ms, and you also get the embed code to put the image on your own site, like so:

The embed code for the above is exceedingly simple:

<script src="http://zoom.it/l6BK.js?width=auto&height=400px"></script>

Labels: , , , ,

Wednesday, July 21, 2010

SwiftKey

Also features A few*** weeks ago I installed Swype on my droid and promptly posted a boot blog post from my phone using the new keyboard.  It went reasonably well,  but it caused me to accidentally submit the post halfway through.

Nevertheless,  Swype quickly became my preferred input method on my phone.  Until tonight.

Tonight I installed SwiftKey.  SwiftKey is much more like a regular keyboard in that you type your letters (rather than draw a path over the letters, like in Swype), but the HUGE differentiator that SwiftKey brings to the table is that it predicts the NEXT word you're going to type.  Let me say that again: SwiftKey predicts the NEXT word you're going to type!  It does this through a combination of statistical analysis of the language of your choice and what you have typed in the past.  Rather than merely working reasonably well,  SwiftKey really works REMARKABLY well.  So well in fact that it predicted each of the last seven words in the sentence I repeated above.

Not only that, but it also works with the Droid's slide out keyboard,  bringing the best of tactile and predictable typing together.

This is a good one,  and a worthy installation for any (an)droid user out there.   Let's hope it's not too expensive when it comes out of beta.

PS!  Would love to see this on an iPad.

SwiftKey vs Standard Keyboard

SwiftKey vs Swype–a very close call, though the Swyper is hardly using Swype to its fullest.

Labels: , , ,

Monday, July 12, 2010

Yet another pre-stolen idea: the electric supercharger

In my not-too-consistent series of “pre-stolen ideas”, here’s another from the automotive front: the electric supercharger, as part of EcoMotors’ new engine design.

Based on my unused mechanical engineering degree, AFAIK, some of the drawbacks of a supercharger are the additional engine friction it provides, and the fact that the boost provided is directly related to engine speed. Since you only really need the additional boost some of the time, my thought was - why not control boost with a near-zero lag electric motor whose output is completely independent from that of the main engine?  Which is of course what EcoMotors is now doing.

Volkswagen is using a twincharger design in their latest creation – a 1.4 liter engine that produces as much power as V6 engines twice the size did a decade or so ago.  EcoMotors seem to have done VW one better, enough for Bill Gates to invest in the company.

Labels: , , ,

Friday, July 02, 2010

Norwegian Cinema At Its Finest

Java 4 Ever

(thanks, Steve)

Labels: , ,

Bing Bar Begone

I rarely use Firefox anymore, because it takes forever and a half to launch (I should figure out why that is…).  Anyhow, I started it today, just to find the frickin’ Bing bar taking up new real estate.  Where did that come from?

image

Mozilla support has the answer: https://support.mozilla.com/en-US/kb/Removing+the+Search+Helper+Extension+and+Bing+Bar

This is the kind of crap that Old Microsoft would do.  With all the recent goodness coming out of Redmond, I really didn’t expect this.  Bad Microsoft, bad.

Uninstalled.

Labels: , , , ,

Saturday, June 26, 2010

Undersore.js Performance Tests Revisited (this time with pretty charts)

Out of sheer vanity, I added my own blog feed to my Google Reader, as I was curious if anyone ever Liked my posts.
Answer: Nope. :-(

Anyhow, I came across my post on Underscore.js, and since MS just dropped Platform Preview 3 of IE 9, I thought I’d redo the comparison in Chrome6, IE8 and IE9 (though I know this is hardly any complete benchmark test, it’s still telling).  The results are below: 

As I said in my last post, I can’t wait for IE9 to replace every previous IE version…  I haven’t been this excited about an IE product since IE4, which was more than 10 years ago.

IE 8 – still a dog.

IE8 results

IE 9 PP3 – Starting to look good!  Faster than Chrome in some tests!

IE9 results

Chrome 6 – still the winner in most categories, though the lead is shrinking

Chrome 6 results

Bottom line, though – if you’re doing a lot of looping/mapping, you should use Underscore rather than jQuery.

Labels: , , , , ,

Friday, June 18, 2010

Re: Swype on my Droid

... Oops. And that's what happens when you try to post from your phone using a brand new input device.  As I was saying it reminds me of back in the day when I had a handspring (palm) and I had to learn graffiti. Everything is familiar, yet so very Very different. I don't think I am yet back up at the same speed re that I was at before I switched, but part of that is me simply not trusting myself that I actually know where the letters are on the keyboard (I Do, Really!), and part is simply trusting Swype to do what it is supposed to do, which it does remarkably well, most of the time. (ironically typing, er, swyping that last sentence was quite difficult...).

What is particularly impressive about swype is how amazingly sloppily you can draw the path over the letters and how swype still figures out what you're trying to spell. I assume that when I start trusting both myself and swype more, I won't want to go back, and when I do, I still have my droid slide out keyboard.

Recommended.

On Jun 18, 2010 9:24 PM, "Oskar Austegard" <austegard@gmail.com> wrote:

I installed the Swype beta the other day on my Droid, and today made it my default keyboard. It's been an interesting experience, figuring out how to use a completely new input device. In many ways it remind s me

Swype on my Droid

I installed the Swype beta the other day on my Droid, and today made it my default keyboard. It's been an interesting experience, figuring out how to use a completely new input device. In many ways it remind s me

Sunday, June 13, 2010

IE 9 HTML5 Testing: “Works on My Machine”

One of my esteemed colleagues on an internal forum posted about how great IE 9’s HTML5 support was, based on the result of Microsoft’s test pages.  MS’s tests are sadly self-selective however: meaning they only seem to test for elements that IE9 supports: http://samples.msdn.microsoft.com/ietestcenter/

“Cross-browser Test Results Summary:
W3C Web Standards Number of Submitted Tests Internet Explorer 9
Platform Preview
Mozilla Firefox 3.6.3 Opera 10.52 Apple Safari 4.05 Google Chrome 4.1
HTML5 40 78% 63% 48% 43% 43%
...”

Compare that to my own results running html5test.com on the 6(!) browsers I have installed:

html5test

Html5 is the first time in a decade that the browser vendors have had a new major standard to fight over; I’m just grateful that this time around we’ll have an army of frameworks such as jQuery that can level the development playing field for us.

Labels: , , , , , , , , ,

Friday, June 11, 2010

How to Always Run Visual Studio As Administrator

To jum straight to the solution, click here

“Certain tasks, including debugging and creating local IIS applications, require that you start Visual Studio as a user with Administrative privileges. On Windows Vista, and Windows Server 2008 when not running as the built-in Administrator account, this requires right-clicking the Visual Studio 2008 icon in the Start Menu and choosing Run as administrator.

“To make this process easier, you can create a shortcut and check the Run this program as an administrator check box on the Compatibility tab of the shortcut properties.”
from Using Visual Studio 2008 with IIS 7 @ learn.iis.net

On the last few projects I’ve worked on, we’ve used IIS sites for our development (for a number of reasons I won’t detail here), and the need to open VS in admin mode has been a constant annoyance.  It’s like constantly getting bitten by a mosquito. Today I finally got annoyed enough to spend 5 minutes researching a solution.  (I know.  I procrastinate.)

The solution, or what seems to be working for me so far at least was found at sevenforums.com: How to Run a Program as an Administrator in Windows 7.  Some of these options I knew about, the one I hadn’t tried and which worked for me was this:

1. Right click on the program shortcut or program .exe file, then click on Properties, and on the Compatibility tab. (See screenshots below)
NOTE: If you are doing this while logged on as a standard user instead of an administrator, then you will need to also click on the Change settings for all users button and type in the administrator's password.

Run as Administrator-compatibility_mode1.jpgRun as Administrator-compatibility_mode2.jpg

2. To Always Run this Program as an Administrator -

A) Check the Run this program as an administrator box, and click on OK. (See screenshots above)

The key is to change the compatibility setting of the Visual Studio EXECUTABLE, not the shortcut to it.  I.e., on my laptop, I went to C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ and right-clicked devenv.exe and then proceeded as above.

I then had to add one more step – when I now clicked on a .sln file, nothing would happen.  It appears the default Open action couldn’t run, I assume, due to inadequate privileges.  To fix this, I right-clicked the .sln file, selected Open With –> Choose Default Program, and then selected Visual Studio, making sure Always use… was checked.

Presto – my .sln files now open asking to be run as admin, as do my jump list projects.

Itch scratched.

Labels: , , , , , , , ,

Wednesday, June 09, 2010

“Old school’s not cool.”

Well, this is certainly an interesting way to determine staleness: stability ;-)

image

But OK, fine – update to Chrome 6.0.427.0 if you must.  At this rate Chrome will have the highest version number of any browser within a year or two (take that Opera!)

Labels: , ,

Thursday, June 03, 2010

Diva Girl in Mommy’s sunglasses

I rather like the new personalized background picture for Google – even if it is a blatant rip off of Bing.  Once again, competition improves the field.  Here’s my current background – from our trip to Philly last weekend:

image

Labels: , , , , ,

Thursday, May 27, 2010

Enabling Support for HTML 5 Schema Validation in Visual Studio 2010

Out of the box, HTML 5 schema validation is not supported in Visual Studio 2008 and 2010.  The folks on the Visual Web Developer Team rectified this for VS 2008 and Visual Web Developer, but they did not provide any update for VS 2010 (that I know of).  No matter, you can use the 2008 version – here’s how.

1. Download the schema update for VS 2008/VWD

2. Open the downloaded zip file and follow the instructions in the ReadMe.txt file except:

2.a) Where it says to add the schema to C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Packages\schemas\html, replace the 9.0 with 10.0 – the path for VS 2010 (in 64 bit Windows) is:

C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Packages\schemas\html

2.b) Edit the VS registry file matching your Windows environment, and again change the 9.0 to 10.0 – e.g. for my Windows 7 64 bit machine the correct registry file is:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Packages\{1B437D20-F8FE-11D2-A6AE-00104BCC7269}\Schemas\Schema 23]
"File"="html\\html_5.xsd"
"Friendly Name"="HTML 5"
"URI"="http://schemas.microsoft.com/intellisense/html-5"

3. Back up your registry

4. Run the registry file (as always, take caution)

Labels: , , ,

Wednesday, May 26, 2010

Uh Huh - iPad Ad Coordination FAIL

There’s a new iPad print ad campaign out, obviously (?) as a reaction to the whole Flash controversy.  It shows a hip (?) young(?) female (I hope) watching a Juliette Lewis video on vimeo.  Too bad the rest of us can’t….

AdFail1

AdFail2 AdFail3

PS! Interesting to see the lag between the ad creation and the release date

PPS! vimeo uses a mainframe?

Labels: , ,

Monday, May 24, 2010

Comparative Performance of Underscore.js in Chrome and IE

I came across the very handy-looking Undersore.js today, and clicked on the test & benchmark link. I first ran the test in Chrome.  The results below show number of operations per second.  Looks like each, map, keys, values, and range are pretty inexpensive operations, whereas uniq and intersect should be used sparingly.  All makes sense. 

Then out of curiosity, I ran the same tests in IE and Firefox.  The exact numbers are not significant as the results vary by 10-20% between subsequent runs in the same browser, but the range is pretty illustrative.  And yes, I know IE9 is harder, better, faster, stronger, so this is not a fair fight.  I can’t wait for IE9 to replace every previous IE version…

  Ops/sec

(higher is

better)
Test Chrome 6 IE 8 Firefox 3.6

_.each()

20213

510

3249

_(list).each()

13570

493

3161

jQuery.each()

3637

209

910

_.map()

18581

303

5488

jQuery.map()

7084

686

8519

_.pluck()

10852

282

4785

_.uniq()

127

1

33

_.uniq() (sorted)

308

210

84

_.sortBy()

1641

45

359

_.isEqual()

4962

869

1826

_.keys()

22675

1142

4295

_.values()

24551

321

5435

_.intersect()

83

1

20

_.range()

33345

1223

5262

Again, why I use Chrome as my default browser.

Labels: , , , , ,

Sunday, May 09, 2010

Oops - “spellcheck any multiligual texts…”

So I was responding to an internal developer forum request for recommendations for a WYSIWYG html editor with spell check.  I was going to recommend Telerik’s Editor and related RadSpell component.  Not so sure any more…

multiligual spellcheck

Cobbler. Children.  All that.

Labels: , , , , ,

Wednesday, May 05, 2010

Erik and Lottie at Adam and Cari’s Wedding

…or - "the difference between Age 4 and Age 2"

image

image

Thanks, Cari and Adam!

Labels:

Friday, April 30, 2010

Fun with 1000 Rolling Stone covers, AndreaMosaic and the Deep Zoom Composer

Having finished helping Rolling Stone magazine put their archive online (our company, AIS, together with Bondi Digital, did the Silverlight-based archive portion (more on the project later, potentially), another company did the main site), I decided to get artsy by generating a mosaic of the latest issue cover, by using thumbnails of some 1000 previous covers.

mosaic partial zoom

AndreaMosaic worked beautifully in creating the mosaic, and even pre-generating the starting point for a Deep Zoom image.  I opened that in Deep Zoom Composer, and generated both a Silverlight and an Seadragon Ajax version of the composite.  I then uploaded the whole shebang to my public s3 bucket.

It all took a bit of fiddling to get right, but if I had to do it again I could probably do the whole thing in 5-10 minutes…  It’s that easy. (Seriously, this blog post is taking longer…)

Of course, now that I’m putting in all the links in this post, I realize I could have simply hosted this at seadragon.com…  Oops.

UPDATE:Since MS is so kind to do the processing for me, I figured I might as well create a bigger version of this. The following is around 180MP, made up of 3000 tiles, each 300px tall... Click the full screen button in the embedded viewer for the best effect.

Update, May 12th: ...and here's the latest 2-page cover:

Labels: , , , , , ,

Thursday, April 08, 2010

Uri Properties

For the life of me I can never remember what each property of the Uri class is meant to return.  SnippetCompiler to the rescue:

public static void RunSnippet()
{
  Uri foo = new Uri("http://some.domain.com/folder/file.htm?param=val#frag");
    foreach(PropertyInfo pi in foo.GetType().GetProperties()){
      if (pi.CanRead) {
        WL("{0}: {1}", pi.Name, pi.GetValue(foo, null));
      }
    }
}

Make sure using System.Reflection; and using System.Web; are is included, and there you have it:

AbsolutePath: /folder/file.htm
AbsoluteUri: http://some.domain.com/folder/file.htm?param=val#frag
Authority: some.domain.com
Host: some.domain.com
HostNameType: Dns
IsDefaultPort: True
IsFile: False
IsLoopback: False
IsUnc: False
LocalPath: /folder/file.htm
PathAndQuery: /folder/file.htm?param=val
Port: 80
Query: ?param=val
Fragment: #frag
Scheme: http
OriginalString: http://some.domain.com/folder/file.htm?param=val#frag
DnsSafeHost: some.domain.com
IsAbsoluteUri: True
Segments: System.String[]
UserEscaped: False
UserInfo:

UPDATE:  Steve Michellotti just showed me how this works beautifully in LinqPad as well, just set the language to C# Statement(s), replace WL with Console.WriteLine and you’re good to go.

Labels: , , , ,

Wednesday, March 17, 2010

Odd MINOR Outlook 2007 Bug

First message: sent 12:34, from EST timezoneSent1234

Second message: sent 12:59, also from EST timezone – note the discrepancy between list and preview.

sent1259

Labels: , ,

Thursday, March 04, 2010

The Lottie (age 687 days) Numeral System

0 = “All Gone” or “All Done”

1 = “One”

2 = “Two”

> 2 = “Two”, or “One More”

Sequence: “One, Three, Four, Eight, Ten”

Labels: , ,

Friday, February 12, 2010

Things I’m digging today

FreeMind – free mind mapping tool.  Love the simplicity, and that I can copy a branch and paste in an email as a well-formatted nested list.

Fiddler2 – back in the day (v1.x) I remember it as complex to use – now it’s dead simple.  Maybe I got smarter, but I fear the reality is that the tool just got better.

Buzz – I, for one, welcome our new insect overlords

(Ok, I admit it – I just wanted to see how my blog posts appeared on Buzz, and I had nothing better to write.)

Labels: , , , , ,

Tuesday, January 26, 2010

Testing sms to blog functionality. Not sure why i'd do this instead of blogging by email, but (geeky) cool nonetheless...

Tuesday, January 19, 2010

Today’s Prediction: Republicans beat Democrats 41-59

“See, it’s not that the democrats are playing checkers and the republicans are playing chess.  It’s that the republicans are playing chess, and the democrats are in the nurse’s office because once again they’ve glued their balls to their thighs.”
- Jon Stewart @09:10/10:05

Labels: , ,

Tuesday, January 12, 2010

Mission Failure

Just read a notice from BlackBerry that there is a software update for my phone.  Not only did they completely gfail to sell me on the upgrade (what’s new?), they inject such a barrage of technical-ese that anyone’s eyes would glaze over.

Something tells me Apple would not have sent the same kind of email – see highlighted section below…

BlackBerry Software Update Notification
Update Today!
----------------------------------------------------
What else can your BlackBerry® smartphone do for you?

Find out when you update to the latest smartphone software! This free update is ready and waiting to help you do more with your BlackBerry smartphone. To update today visit http://www.blackberry.com/updates

New ways to work and play!

   * As an aid to comprehension, this section provides a brief overview of the life-cycle of a device upgrade.  * Each OTASL capable device will contain one or more OTASL Service Records(SR) each identifying a Device Manager (DM). The DM may be located at RIM, may be part of a BES or, in future, could be associated with a 3rd party application provider. Each SR will identify the applications which are of interest to the corresponding DM. SRs may be delivered by PRV, BES or in an upgrade application loaded OTA. … (it goes on, but there’s no point).

Labels: , , , ,

Monday, January 11, 2010

Well, I guess it’s settled then.

Me: "Who did you play with today, Erik?"

- "Divon... and Riley, when I grow up, you know daddy, when I grow up I'm gonna marry Riley!"

"Really?"

- "Yeah! Cause we're the same color!"

"Huh?"

- "Yeah, we're both light!  And you're light and mommy's light and I'm light and Lottie's light, so.."

"You know you don't have to marry someone who has the same skin color as you, Erik - you can marry anybody you like!"

- "You can?  ... I'm gonna marry Riley.  And when I grow up, I'm gonna be a dogtornarian!"

"Really - a dogtornarian?"

- "Yeah, a dogtornarian is a doctor for dogs.  And he gives the dogs shots, and the dogs are really good, and they get a flu shot so they don't get sick!  And when Riley grows up, she's gonna be a vegternarian, but she's only going to treat cats, and we're gonna treat both dogs AND cats!  And we're gonna have a little baby, and  the baby is going to to a school, and we're going to go to work!  Just like Lottie and me go to school, and you and mommy go to work!"

...

- "Daddy, we're having a great conbersation, do you like it?"

"Yes, Erik, I do.  A lot."

Labels: , ,

Wednesday, January 06, 2010

MVC Route Constraint to Exclude Values

For Album Credits I wanted to allow personalized urls of the format http://albumcredits.com/yournamehere.  This turned out to be quite an interesting routing exercise.

Since this is an MVC app, our standard url format is of the usual http://albumcredits.com/{controller}/{action}/{index} kind, and for some pages, I need to allow the url to simply specify the controller, defaulting the action to index – again, the usual ASP.NET MVC pattern.

I was familiar with the constraint parameter option for the AddRoute method, but had never studied it in much detail – we’d used it to limit certain indexes to be numeric, but that was all.  For the root-level personalized urls we needed a more robust constraint – specifically we needed to exclude any controller from the list of valid personalized Urls.

I first spent more time than I cared to trying to come up with a regular expression pattern that would NOT match the list of controller names – it looked something like this:
^(?:(?!\b(foo|bar)\b).)*$
(thanks to Justin Poliey/stackoverflow.com) where foo and bar, etc were the controller names to NOT match.

Not until after I got that to work did I think to google “mvc custom route constraint”.  Of course the MS MVC team was smarter than that – custom route constraints are really very straight forward…

For my purposes, I went with David Hayden’s approach – the code below is essentially the same as his, just with the logic reversed.

using System;
using System.Linq;
using System.Web;
using System.Web.Routing;

namespace AlbumCredits.Web
{
	/// <summary>
	/// Route constraint that returns true if the parameter value is not one of the excluded values.
	/// </summary>
	/// <example>A controller constraint like 
	/// <code>new { controller = new ExcludeValuesConstraint("foo", "bar") }</code>
	/// will match "blah" or "snort" but will not match "foo" or "bar".
	/// </example>
	public class ExcludeValuesConstraint : IRouteConstraint
	{
		private readonly string[] _excludeValues;
		/// <summary>
		/// Initializes a new instance of the <see cref="ExcludeValuesConstraint"/> class.
		/// Example: <code>new { controller = new ExcludeValuesConstraint("foo", "bar") }</code>
		/// will match "blah" or "snort" but will not match "foo" or "bar".
		/// </summary>
		/// <param name="excludeValues">The excluded values.</param>
		public ExcludeValuesConstraint(params string[] excludeValues)
		{
			_excludeValues = excludeValues;
		}

		/// <summary>
		/// Determines whether the URL parameter contains a valid value for this constraint.
		/// </summary>
		/// <param name="httpContext">An object that encapsulates information about the HTTP request.</param>
		/// <param name="route">The object that this constraint belongs to.</param>
		/// <param name="parameterName">The name of the parameter that is being checked.</param>
		/// <param name="values">An object that contains the parameters for the URL.</param>
		/// <param name="routeDirection">An object that indicates whether the constraint check is being performed when an incoming request is being handled or when a URL is being generated.</param>
		/// <returns>
		/// true if the URL parameter contains a valid value; otherwise, false.
		/// </returns>
		public bool Match(HttpContextBase httpContext, Route route, string parameterName, 
			RouteValueDictionary values, RouteDirection routeDirection)
		{
			return !(_excludeValues.Contains(values[parameterName].ToString(), StringComparer.InvariantCultureIgnoreCase));
		}
	}
}

I can now use this when setting up my Route Table like this:

	routes.MapRoute("PersonalizedUrl",
		/* for urls like  */ "{personalizedUrl}",
		/* route defaults */ new { controller = MVC.Profile.Name, action = MVC.Profile.Actions.IndexByPersonalizedUrl, personalizedUrl = string.Empty },
		/* where          */ new { personalizedUrl = new ExcludeValuesConstraint(ControllerNameArray) }
	);

Labels: , , ,

Friday, December 04, 2009

Getting the ContentType from an ItemAdding Event Handler

Inside an event handler for an ItemAdded event, getting the List Item’s ContentType is as easy as

var contentType = properties.ListItem.ContentType;

However, for ItemAdding, properties.ListItem is null.

Luckily, the ContentType name and Id are part of the properties.AfterProperties collection – the following will work:

SPList list = properties.List; 
string contentTypeName = properties.AfterProperties["ContentType"].ToString(); 
SPContentType contentType = list.ContentTypes[contentTypeName]; 
SPFieldCollection fields = contentType.Fields;

Between the AfterProperties field values and the content type field collection, you typically have all that you need... Just remember to not depend on properties.ListItem.

Labels: , , , , ,

Wednesday, December 02, 2009

SharePoint 2010: Managed Metadata fields and the TaxonomyHiddenList

Notes to self and others:

When you create a Managed Metadata (aka Taxonomy) field in a SharePoint 2010 list or library, the field’s schema will look something like this:

<field id="{f6d2b908-4ed4-42f8-a491-e1177ed57596}" version="1"
rowordinal="0" colname="int3" name="Tags" staticname="Tags"
sourceid="{58701f50-42a0-4c3d-8fdd-fb6f3a798bc4}"
enforceuniquevalues="FALSE" required="FALSE"
showfield="Term1033"
webid="956683ae-54b0-46c4-8fe6-8e14309b6fcd"
list="{4c231f71-5ed3-49aa-a62f-3fbb9a900bd0}"
displayname="Tags" type="TaxonomyFieldType">

<default>1;#A|6832dce7-bd84-4afc-8311-d5a1367dc282</default> <customization> <arrayofproperty> <property> <name>SspId</name> <value xmlns:p4="x-instance" p4:type="q1:string"
xmlns:q1="x">5dc61acc-dfa4-41dd-aa85-dd71d054ab1f</value> </property> <property> <name>GroupId</name> </property> ...

(field definition and namespaces shortened for readability)

Some of the notable attributes are:

  • Type – obvious
  • WebId - The current list’s web
  • SourceID - The current list’s id
  • List - The ID of a “TaxonomyHiddenList” which resides in the current web, but as the name implies, is hidden.
  • ShowField - the field in the TaxonomyHiddenList to display – looks like it’s locale enabled.
  • The SspId property is also crucial – it is the TermStore ID used to access the TermSet – more on that in another blog post…

The TaxonomyHiddenList’s schema looks like most lists’ schema – HUGE.  Some of the interesting fields are:

  • IdForTerm - in the case of the default value above (A) this field’s value matches the GUID 6832dce7-bd84-4afc-8311-d5a1367dc282
  • IdForTermSet - this appears to be the term set id from the MM data store – I have another column in my list which is not tied to a centrally managed metadata store – its value shows as 0000….-00… etc.
  • IdForTermStore – in my instance, this GUID is the same for both the managed and non-managed metadata field – matches the SspId above.

Labels: , ,