This blog has, IMO, some great resources. Unfortunately, some of those resources are becoming less relevant. I'm still blogging, learning tech and helping others...please find me at my new home on http://www.jameschambers.com/.

Wednesday, March 31, 2010

jQuery AutoComplete with ASP.NET MVC

At the time of this post, I am using Visual Studio 2010 Ultimate RC1.

I recently posted an entry on using a common jQuery plugin that added auto-complete functionality to a textbox. The jQuery UI team has just added a component to the library that provided a more streamlined implementation, closer to the feel of other components and with similar syntax for initiation, events and methods.

The widget actually appears to be authored by the same programmer, only with a much stricter focus on adhering to the jQuery style.

This is a great move and the component has really upped the ante for this release as it’s moved to the core jQuery UI library.

Scroll to near the end to get a point-form walk through. The very end of my post includes a project download.

Revamp or Rewrite?

There will be a few people who are locked into a particular build of a component, who inherit some code or are otherwise just interested in an older version for whatever reason. There are also some important changes to get the new autocomplete to work, as well as some things we no longer need to do. Some of those tricks may be relevant to other plugins, so I’m leaving my original post intact.

My last post was also just a list of things you’d need to do differently from a separate walk-through, so I’m taking this opportunity to write a complete run.

Prerequisites

If you want to follow along with this post you’ll need the following goodies:

  • Visual Studio 2010
  • The jQuery UI library downloaded with the jQuery library (and any theme you like) rolled in
  • I usually also grab the latest VSDOC file so that I get intellisense in the IDE.

Basic Setup Tasks

Finally. Some meat! We’re going to do the following:

  • Create an ASP.NET MVC project
  • Configure the project (overcome a minor template bug)
  • Add the JS and theme files to the project
  • Create a master page and setup the includes needed

Okay, let’s go. Crack open Visual Studio and navigate to the new project dialog. To filter the list of project types down, select ‘Web’ and then click on ASP.NET MVC 2 Empty Web Application.

Because of an omission in the template for this project type you’ll need to add two lines in the web.config yourself. This is the web.config located in the root of the project. Make sure your assemblies section contains the lines located here.

Next, we need to get jQuery up to speed (the autocomplete widget requires a newer library), and make our site aware of it. In the Solution Explorer, open up the scripts folder and delete the three 1.3.2 files for jQuery.

image

Drill into your jQuery UI theme download and get the files from the JS directory. Add those to the script folder in your project. Add the VSDOC file as well, if you’re using it.

imageWe also have to get the theme implemented (if you are so inclinded). Right-click on your project and add a new folder called Content. Copy the themes directory from your jQuery download and paste it in the Content folder your just created.

Now we’ll get our project started by adding a master page to the mix. On your Views –> Shared project folder, right-click and add a new item. Select MVC 2 View Master Page from the list and call it Site.Master because all the cool cats do. In the head tag of the page add the scripts we need to light up the plugin.

image

If you’re using a theme, you’ll also want to include the required style sheets to make everything appear correctly as I have above. You can easily add the above references by dragging them from Solution Explorer to your head section.

A Simple Start

Let’s test at this point to make sure we’re setup correctly. In this section we’re going to do the following:

  • Add a Home controller
  • Add a default view (Index) to the project
  • Create a div that will be styled to reflect a properly configured style sheet
  • Add a small block of code to ensure jQuery is rigged up correctly

Right-click on the Controllers project folder and select Add –> Controller. I’ve used HomeController as the name as it’s the convention used by most.

image A very simple class is created for you that represents the first controller. At this point, right-click on the method name “Index” and select “Add View…” from the context menu. The default options work for me (Index as the name, not a partial view, not strongly typed, use the master page I just created).

Side note: because the default route is set up for us in Global.asax, our Home controller with the Index action method will be used for requests to the default document on our site.

To make sure our site is rigged with jQuery and the proper styling, add the following markup to the page:

<div id="test-panel" class="ui-state-default">
This panel will disappear on command.</div>

<script type="text/javascript" language="javascript">
$(function () {
$('#test-panel').click(function(){
$(this).slideUp();
});
});
</script>

We should be good to go for our test! Run the app (F5). You may be prompted to modify the web config…do that and watch the page come up. Clicking on the div shows that jQuery is lit up and we’re good to go. Your page should look similar to this:

image

If clicking the panel doesn’t make it slide up or you do not have the shading on the div you should go back and make sure you’ve not missed any steps.

Lighting up Autocomplete

I want to demonstrate the basic functionality of the widget, but I also want to ensure that we’re following some of the practices commonly used in MVC projects. Here’s where we’re going to start:

  • Clean up our index view
  • Add a textbox to the view
  • Add a model class and a corresponding repository that returns a fake set of data
  • Create a PartialViewResult method that can be used to retrieve the data
  • Add the script needed to call our controller’s action and populate the autocomplete box

Start by quickly removing any of the test code we created, but leave the script block in place as we can reuse that. All that should remain inside your content placeholder is the page title and said block. Add an input with an ID of “name-list” to the page and you should be setup like so:

image

In your Solution Explorer, right-click on Models and add an new class called Person. Add two properties, an int for the PersonId and a string for FullName. This class took about 4 seconds to write as I used the prop code snippet (type “prop” then tab-tab). It’s not a terribly complicated class to begin with, but it’s a great shortcut!

image

Add another class to the Model folder called PersonRepository. Create an internal method in it of type List<Person> called FindPeople. The method should accept a string for the search text and an int for the max number of rows to return.

image

This is just a simple method with a LINQ query to filter the list. We also cap the number of results with the Take() method.

I have omitted some code above; what I have there is a whole bunch of random names added to the names list. The code is in the project download and I got the random names from this site.

With our model and repository in place, we’ll next create the method to be called by the autocomplete plugin to get our list of results.

Side note: We have to be aware that binding will occur to the parameters of the post automatically for us and that reflection is used to map the variables. This is case sensitive and, at the current time, there is no tooling support to make sure we get this right. Your request will just fail in transit and you won’t see anything in the browser. If you’re experiencing this, I highly recommend downloaded FireFox and FireBug to capture and view the requests/responses at play.

I find the following interesting points to mention of the following code:

  • We are using an HttpPost to help prevent scripting attacks or data exposure from direct JSON queries
  • We use a JsonResult as the return type on the method
  • Json() is used to convert our List<Person> – the response type from the repository’s FindPeople method – to the proper JSON notation
  • The default behaviour of Json() does not allow GET (but you can override this if required)

image

And finally, we’re going to write a short burst of JavaScript to complete the mix. At this point we’re only specifying the source but here are some observations:

  • We use a function as the ‘source’ property to post data to our controller action
  • The function uses an ajax call with the path to the action
  • We specify that we’re using POST and that the data is formatted as JSON data
  • We define a success method to map the data of the response back to an item array of our format
    • label and value properties are used by plugin
    • we can store additional data in the result (for example, the id) for later use

The contents of the script block should be as follows:

image

That’s it?

Yeup. That’s it. Press F5 to run the application and you’ll be able to start auto-completing some things that you type.

Here’s an overview of the steps required, without the bits for the setup testing:

  • Create the VS2010 ASP.NET MVC 2 empty project
  • Correct web.config’s assembly references
  • Add the appropriate jQuery and jQuery UI libraries to the project
  • Create a master page and add the script and CSS references
  • Create a Home controller with an Index action
  • Implement a repository that accepts search criteria and returns model data
  • Write a JsonResult method with an HttpPost attribute which accepts search parameters and calls the repository
  • Use jQuery to rig-up a text input with the call to the controller action

But what if you want to do something interesting with the result of the user’s selection?

Good question, and it’s what got me started on this whole thing.

The Fun Bits

If you are working with a data-driven site (and likely you are, if you’re in any modern web programming environment) you know that IDs are king.

Luckily we are able to store as complex an object as required in the JSON result. The PersonId from my Person model was stored in the UI element, just as was the display name.

Here is the success function extracted to show the ID getting stored:

image

So, how do we get it out? Autocomplete actually keeps track of the array for us and allows us to access the selected item when the select event fires. We define a function for this event and pass it in as one of the options for Autocomplete with a couple of parameters. We can then access any properties we attached to the array when we parsed it above:

image

Now, simply access the ui.item object and any of the properties you setup in the success parser will be available. You can do much more interesting things than just alert(), obviously, but this demonstrates how easy it is to use the plugin with dynamic data where IDs are required.

Conclusion

The addition of Autocomplete as a widget to jQuery UI is a welcome and surprisingly mature component. You will find that with a few setup points and relatively painless coding you will be able to add AJAX-enabled autocomplete functionality to a textbox. It’s also clear that ASP.NET MVC is well suited to integrate with this type of behaviour.

Download the project file here.

Tuesday, March 23, 2010

Windows Phone 7 Series Development – Allowing the User to Choose a Photo

I am using the WP7 SDK from March 2010 at the time of this post.

I’ve been working on the SDK the last few days and am really enjoying it. I’ve hit a few roadblock in the ‘tasks’ department and am hoping to find a workable solution soon.

At this time, it does not appear that the emulator is ready for some types of application development and testing, specifically related to work in the Microsoft.Phone.Tasks namespace.

A little fun, first

image

I think it would be hilarious if everyone downloaded the emulator for Windows Phone 7 Series and started hitting Apple’s site from IE.

I don’t think they’d care, but it would still be funny.

MSDN Struggles

So, we have a few things to work from if we want to get the user to pick a photo. Say you’ve got an application that would allow them to send a photo to a friend or upload it to a service on the cloud.

The first thing they’ll need to do, obviously, is to pick the photo they want to work with. This actually looks like a trivial task.

In the Microsoft.Phone.Tasks namespace we have a series of helpers that give the user a consistent “Windows Phone” look and feel from within our applications. Here are some examples:

  • BingMapsTask
  • CameraCaptureTask
  • EmailAddressChooserTask
  • EmailComposeTask
  • PhoneCallTask
  • PhoneNumberChooserTask
  • PhotoChooserTask
  • SaveEmailAddressTask
  • SavePhoneNumberAddressTask
  • SearchTask
  • SMSComposeTask

We’re going to be able to offer a deep level of integration with the phone experience. Unfortunately, we’re working in a bit of a void right now.

The documentation suggests that, when executed, these tasks will return there results on the Page’s OnChooserReturn event. The signature is simply:

void OnChooserReturn(object sender, EventArgs e)

The single entry point concept here (all task results will come in on the same event handler) suggests that we’re going to want to use the Rx (Reactive) framework to sort out the details.

But how do we get at our result?

imageMSDN lists a ChooserEventArgs object that gives us access to the result. This is a generic class, with the task-specific result type defining the result. But how do we pull it?

There are no examples at this point, so I can only assume we’re going to cast it from the EventArgs we get in OnChooserReturn. We’ll use reflection to test (likely, this is where we’ll put Rx to work) then handle the result as appropriate.

As you can see from the emulator screen shot, I can’t go any further to test, explore or prove this as cannot execute the Tasks listed above with the current tools. Instead, we are presented with the following COMException:

The drive cannot locate a specific area or track on the disk.

The PhotoResult class (returned from the CameraCaptureTask and the PhotoChooserTask) will be the type I funnel in on when this functionality is lit up.

The Good and the Bad

I’m loving this direction. The Rx Framework is all about applications that live and respond to an environment and doing that asynchronously. Funnelling the results of environment actions by the user through a single event on a page allow us to behave that way as well.

Because we get access to the resultant object by overriding the event handler on the page, we will be able to have each page in our application respond differently – in context – when the event fires. I think this is a fairly clean approach and hopefully encourage developers to design specific contexts for their applications.

There are two negatives from my perspective right now:

  1. Lack of code samples – this one will work itself out. As the community jumps on board we’ll see the samples popping up. I hope I can contribute in this area, too. MSDN will also move towards a more complete state if Microsoft follows through on their commitment to developers in this space.
  2. Lack of emulator support – this will be a big pile of suck if it doesn’t get implemented. I’m hopeful that there will be an integrated photo store, or a way to push photos to the device in such a way that the emulator sees them as user photos. Also, emulated camera support would be great: let me specify a directory on the computer with photos in it, then choose a random one to return when I ‘take’ a photo in the emulator.

Early Goods

As is always the case when you get in early, the bits are tasty but not filling.

I highly encourage developers to get in on the scene here and push around the SDK.

And PLEASE, if you find out how to get the tasks working in the short term (in the emulator) let me know!

Friday, March 19, 2010

ASP.NET MVC AutoComplete Textbox with jQuery

At the time of this post I am using Visual Studio 2010 RC.

UPDATE: Please see an updated post with a complete walkthrough that demonstrates the new jQuery UI Autocomplete released with jQuery UI 1.8+.

image I am writing an interface to help select communities that are in range of one of our broadcast towers.  The project is written in c# in Visual Studio 2010 and targeting the ASP.NET MVC framework.  I am using jQuery as an aid to this task.

Users have hundreds of communities to choose from. They are pre-loaded into the database, as are the towers.  They have a list of towers in a spreadsheet and each tower has a list of communities that are in range.

A checkbox or multiselect component would be too cumbersome and most of us could type faster, anyway.  The desired interface is an AutoComplete textbox that allows a user to enter a few keystrokes and quickly add communities to a tower.

Starting Point?

There are many examples out there that mash together various controls or frameworks, so this certainly isn’t clear. But the seemingly most-referenced project is Jorn Zaefferer’s jQuery Autocomplete plugin

It hasn’t been touched in a couple of years and the documentation is a little rough, but the blog-o-sphere comes to the rescue here: Joe Cartano’s MVC Diaries.

Joe wrote an intro to this plugin using ASP.NET MVC, which is almost exactly what I needed.  Unfortunately, his post was from over a year ago and didn’t quite work.  Luckily, there is very little to do to bring it up to speed.

The Refresh

If you want to skip the verbiage, download the VS2010 project file here.  It is an empty MVC project with only the parts required to get it running.

Here’s a summary of the changes that I made to Joe’s walk-through:

  • Updated jQuery to 1.3.2
  • Changed the delay to 400ms
  • Changed the controller action to a JsonResult
  • Added search capability to the action
  • Modified the call to be a POST
    • The current release of MVC, by default, blocks GETs for Json results. Your choices are to switch to POST or use JsonRequestBehavior.AllowGet, otherwise you’ll get the following error:

This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.

  • Because of switching to POST, I had to configure the AJAX calls for jQuery: $.ajaxSetup({ type: "POST" });
  • Added an ID to the row template so that I could retrieve it when selected (to support keys for database scenarios, like mine)
  • Added a DIV on the page to display the selected ID in the result() method of the autocomplete.
  • Removed the multi-tag support (don’t need it for my application)
  • Implemented a fake repository so it would be trivial to move to a data scenario

And there you have it. Again, you can download the VS2010 project file here if you would like to walk through this.

References:

This is going to be a Great Ride

Scott Guthrie has posted the “hello world” for building a Windows Phone 7 Series app using Visual Studio 2010 and Silverlight.

imageAbout six months ago I did a pilot project on iPhone development and I must say it left me shaking my head. The IDE was, well, non-existent compared the mature MS platform.

Today, I wake to this blog post from Mr. Guthrie and I’m left shaking my head again: how will you be able to keep developers off of this platform?!

Simplicity and Complexity

If your mom passes away and a 15 year-old nephew says, ‘hey, it’s going to be okay,’ that’s simplicity before complexity. When it’s you’re great uncle, who’s lost his wife, his brother and outlived one of his children, that is simplicity after complexity and it means something completely different.

I think this is the story of development on smart phone platforms today.

The Objective C platform feels like a 15 year pimply kid. Microsoft’s message is quite different: “yeah, we get it.” And it is going to mean all the world of difference in the development world.

I can’t wait to get my hands on my upcoming Dell SX2210T to experience the full joys of this development story…

Wednesday, March 17, 2010

A Better Way to Shop for Apps

I am dual posting this to my blog and the WP7S Backstage, but expanding it here.

The more I think about it, I'm actually really liking the idea of a 3rd Party Hubs for Windows Phone.  I’m actually not sure if ‘Hub’ is the right term here, nor how you would organize it on the phone.

Perhaps, these thoughts would best be thought of as an extension to the Marketplace Microsoft has planned.

My take would be like this:

  1. A development company agrees to the terms and conditions (and periodic reviews) of the Microsoft policies for creating and distributing apps.  The company would be 'certified' by MS, but the certification could be revoked if the company isn't playing along.
  2. That company gets it's own marketplace (or a view inside the marketplace).  It is the user's option to install it, not forced down every user's throat.  Perhaps, as part of the PC integration (or on the phone itself) you can select which marketplaces appear in your search results, etc.
  3. Through that marketplace users are able to a) purchase or trial apps, b) rate the apps AND the marketplace.
  4. App developers will decide which marketplaces it wants to associate with (or marketplaces can court developers) and maintain their own quality standards (user approval, certification, etc.)
  5. The community will decide which apps and marketplaces survive and succeed (and which ones tank).

The problem with iPhone and the App Store is that they have 100 very good apps, a 1000 decent apps and 100,000 pieces of turd.

BUT, if you give me the option to shop at "Joe's Exotic Discount T-Shirts", "Walmart" or "Banana Republic", I know - going in - what to expect for quality.

This would also add the ability to open up “adult” boutiques to those who so choose that path.  Likewise, as a parent (and someone who is not into that content) I could block 18+ markets from showing up in my searches.

If a developer could prove their quality and align with a like-minded store, I think that would be fabulous.

This means that Microsoft’s Marketplace would actually become a collection of boutiques and specialty stores, not a volume-driven box store.

Another “It would be cool if…” Post

At the time of this post I am using Visual Studio 2010 RC.

I very seldom work with “files” in Visual Studio, so it doesn’t make sense to me to have files listed in the “Recent” jump list in Windows 7.

image

In fact, I so rarely work with individual files that, if I do need to work on one, I would likely have to hunt it down through Windows Explorer and thus be able to double-click it.

I work on Solutions. Projects. Not so much files.

So, it would be cool if Visual Studio 2010 would put the projects that I use most in the jump list and leave the files out.

Another “Me being fussy” Rant

There is a solution to this, I’m just being picky.

Visual Studio 2010 lets you pin your favourite/most used projects to the jump list on the Start Page inside the IDE. I tend to turn this page off, however.

In the settings for Startup the IDE team actually gives us a pretty good way to do whatever the heck we want when VIsual Studio launches.

image

On top of half a dozen default options (including ones that let you get at recent projects and solutions easily) you can also create your own custom start-up page.

Part of the Visual Studio Extensibility bits is a set of controls that make it easy to build your own page, which is coded in XAML. The VSX team had a blog post on this back in Beta 1, but I haven’t found an updated reference. What’s there is still mostly relevant, though you’ll find that some of the work in creating a start page (and a sample project) is already there for you.

Tuesday, March 9, 2010

Visual Studio 2010 Wishlist: Augmenting ASP.NET and the IDE

At the time of this post I am using Visual Studio 2010 RC.

Today I am just putting down some ideas that I think are just little nice-to-haves, but from a user experience point of view are also a little frustrating because they (the VS team) are so close yet didn’t quite get it.

I want to be clear: when I say “get it” I am referring to the very small portions of features specific to my rant today. If you’re not using VS2010 – even in it’s RC release – and you’re a developer on the Microsoft stack you’re either crazy or suppressed by your employer. I’ll assume you’re not crazy and send my apologies to your employer.

Visual Studio 2010 is the most significant release from the developer product group of folks in Redmond since the release of the original Visual Studio .NET environment. For which, by the way, I still have my t-shirt from the release event in Calgary. ;o)

I’ve posted some thoughts on VS2010 before, mostly found here.

MVC Awareness in ASPX Sources

Okay, so we’ve got this awesome new Swiss Army Knife toolkit and framework that allows us to feel like web ninjas: ASP.NET MVC. Sure, the MVC bits have been kerplunking around for a couple of years, but there is a cycle that tools and patterns follow and we’re just getting to the height of the tool chain now.

Why, though, when I set a form action to an MVC controller method do I get file not found errors?

image

Here’s what we know:

  • the text is being evaluated
  • the engine supporting the code editor is aware of MVC libraries
  • the page we’re working on is inherited from an MVC ViewPage

So why do I see this:

image

…instead of, say, allowing me to right-click and go to the method? All I’m saying is that if you’re evaluating a form action on an MVC page it’s likely that it’s going to an action on an MVC controller. At least, it could be an action on a controller, so why not check for it? (…and let me go to the definition!).

I know that we have Html.BeginForm and, yes, that does make the warning message go away, but that’s not strongly-typed either and, in most cases, I’m not sure there are benefits of using Html.BeginForm over the specified HTML.

Better “Intentional” Tab Arrangement

I love how the tabs and code editor (and designers, and database query results, etc.) have evolved in Visual Studio. In a multi-monitor work environment it is uber-cool to be able to partition my work space the way I like to.

Side bar: my new dream setup is 3x24” monitors vertical with the ATI Eyefinity hardware for development. I would also keep my “top” monitor setup for my “overhead” view of things (docs, email, pings, utils, etc). This would allow some insane productivity. I digress.

While I have applauded the IDE team for the close-tab-button integrated into the tab/name area already, the new tab behaviour is also one of my pet peeves.

image

Some things I like about it:

  • The ‘x’ to allow me to close the tab without switching to it
  • The ability to drag and partition my workspace into whatever arrangement I like
  • The ability to rearrange tabs in one visual partition or to drag to other partitions

Some things I don’t like:

  • Double-clicking breaks the tab out into a window…I don’t mind this per se, and imagine some like it, but I’d like to be able to turn this off
  • Accidentally dragging the tab slightly when trying to switch to it (even a pixel) will break out the tab into a window. I would prefer a buffer of, say, 3-5 pixels so that the action was more intentional.

I tend to work with two or three partitions and I arrange them in the same way. I am very intentional about this. For example, in my three partition setup, I work with CSS and JavaScript in one work area, ASPX pages and controllers in the second and repositories and other model-related classes in a third.

That said, here is something I wish the IDE did:

  • When I double-click a file in Solution Explorer, and I have multiple work areas open, I would like a way to say which area to send the file to. There would be a number of ways to do this (and here are the first three that come to mind):
    • When CTRL is pressed and a file is double-clicked, put a “ghost” of the file on the cursor and let me click an area.
    • When I hold CTRL and drag a file to an area, open the file there instead of creating a link or giving me an error
    • When I right-click a file, give me a “Send To…” option and let me pick the area (even via simple overlay or something).

Cross-file Script Awareness

There is a cool trick you can use to make use of the VSDOC files that are available for various JavaScript libraries, such as jQuery. It goes something like this:

image

You can also use this trick in your ASCX files which don’t pick up script references in your Site.Master.

This is a good work-around. But it’s not a feature.

I don’t know what the right answer is here as there are a lot of things to consider. Should an ASCX always be aware of it’s context? Should it be written for a specific context? Should it ensure, itself, that scripts will be available to it? Or, in the context of an in-department or in-house application, can’t we assume it will be in the confines of it’s project?

Maybe you could come up with a way to say, “Controls in this directory are aware of these scripts (or stylesheets, etc.)”. Perhaps that would get through this one.

Or, perhaps, this is just an area where the patterns, tools and languages don’t and won’t fit together nicely.

Thursday, March 4, 2010

Returning a LINQ to SQL Image from ASP.NET MVC

I am working in VS2010 RC at the time of this posting.

I am working with a set of images stored in an SQL database in my ASP.NET MVC project. I would like to load the images asynchronously (and preferably effortlessly) and as “in-line” as possible from my pages. I wanted to create a controller action that returned an image.

Ideally, something that works into my page as simply as this:

image

The HTML that would be rendered might be like this (or, I could write it out myself if I don’t want to use the Url helper above):

image

My images were being returned from a LINQ to SQL method (a stored procedure that returned an Image field) and, so, were typed as System.Data.Linq.Binary

A Complicated Mess

I Binged around for a bit but was having trouble finding info that was relevant or entirely up-to-speed with the latest MVC bits. I was frustrated because, without much explanation, people were reverting to complicated HTTP handlers, building System.Drawing.Bitmap objects and subclassing ActionResult (which felt a little weird).

I came up with the following solution (which I wrote in my controller) by gleaning through a ton of different implementations:

public EmptyResult GetImage(int id)
{
Byte[] imageBytes = _repository.GetImage(id).ToArray();

Response.OutputStream.Write(imageBytes, 0, imageBytes.Length);
Response.ContentType = "image/png";

return new EmptyResult();
}



This afforded me the simple notational luxuries as listed above, but it felt a little wrong to be pumping out data to the response stream when I’m describing my method as an EmptyResult.



Easier Without Getting Harder



I didn’t want to run into creating inherited types and the likes without a good reason. This was as complicated as I wanted to get and I wanted to know if I should go further.



I posted a question to StackOverflow to that tune and got back a lead on a couple other candidates to work with. A quick lookup on FileContentResult and I was off to the races:



image



If you like (and to facilitate testing) you can also easily implement a subclass of FileContentResult and pre-set the image type; then all you’d be doing is returning a new PngResult(byteshere).



To Be Fair…



I don’t mean to condemn any of the earlier efforts. In fact, some were pretty ingenious considering the state of MVC over a year ago.



The types that are available now in ASP.NET MVC make it very easy to return an image from a controller action, even if that image is a byte array or stored as a LINQ Binary type.

Monday, March 1, 2010

Use ContentPlaceHolder for Stylesheets on Sub Pages

I highly suspected that the ContentPlaceHolder could be used in MasterPages for styles – we can use it for other things in the header, such as the page title – but had not actually tried it.

imageAs my project grew and individual stylesheets continued to increase in number, the head section of my MasterPage was growing.

This was mostly an experiment of laziness…I had a good 20 pages created and it was working at the start, so I didn’t mind adding to the list of stylesheets in my Site.Master. It got to a point where, pressed for time, I didn’t want to add another ContentPlaceHolder to the Site.Master for fear that I’d not be able to compile and was now looking at over 30 views that needed to be addressed.

I seem to remember getting burned on MasterPages earlier in their life, where there were complications in trying to mix CSS into the header, and problems with the Title tag, etc. I am almost certain that, previously, if you had a ContentPlaceHolder in your MasterPage that you were required to have the corresponding Content tag in your sub page or you’d get an error.

Thankfully, this is not the case…at least not in ASP.NET 4.0.

Error-Free Extension

Thankfully, this is a really easy one to try out. I opened my Site.Master and added the following code to the <head> tag:

<asp:ContentPlaceHolder ID="CssExtensions" runat="server"></asp:ContentPlaceHolder>

I compiled and ran the site, and sure enough, no errors. I was able to hit the 30+ views in the application without any problem.

Next, I moved into the view I was currently developing and added a Content control. I created a new style sheet and added it to the CssExtensions Content area. I then created and applied a style to an image that had not previously been styled.

Running the application again, with no problem, I was pleased to see the style applied in the running site and the proper HTML written to the browser.

Benefits of the Break-Up

I’ll be moving the list of a dozen or so CSS files to their respective sub pages to help reduce the hit taken by the user the first time they visit our site.

Because our primary audience is rural market, specifically those without access to land-based high speed internet, we want to keep our pages small, especially on first load.

Of course, once the user has the file cached there is virtually no perceived performance benefit, but even reducing the number of requests to the server (which caching doesn’t always prevent) might be an advantage for someone still on dial-up.