Ajax Control Toolkit with ASP.NET MVC#

I have been playing with ASP.NET MVC for about 4 months now and have a couple sites, one decent sized, in production right now.  I am very comfortable with it and the extra control over the html is very nice.  Since there is no postback and viewstate in MVC, the Ajax Control Toolkit does not work as designed and needs a few changes to make it work within the MVC framework.  It has forced me to look at jQuery more, and I am really enjoying the simplicity of jQuery's design and the power of using it.  I was just wishing I could use some of the controls in the toolkit and of course i wanted to see if i could get it to work for the sake of making it work.  Well I did get it to work for 2 of the controls so far, some that i use in a normal project.  They are the Calendar and TextBoxWatermark. 

To make this easier, and from a lesson I learned with jQuery, it is best to select your DOM elements by a css class when you can.  This allows for your JavaScript to be more unobtrusive, and ultimately cleaner and easier to maintain.  So i took a couple of methods from the Ajax Futures from last July 2007 and put it in a helper class along with a simple function of mine to allow selection of DOM elements by css very trivial.

To give you an idea of what i am talking about using css selectors for the toolkit, look at this sample:

var elements = $select('TextboxWatermark');
    for (i=0;i<elements.length;i++)
    {
        var elem = elements[i];
        $create(AjaxControlToolkit.TextBoxWatermarkBehavior, {"WatermarkText":elem.title}, null, null, $get(elem.id));
    }

 

I created a helper function $select(className) which basically wraps Microsoft Ajax Futures getElementsByClassName like such:

function $select(className)
{
    var elements = Sys.UI.DomElement.getElementsByClassName(className);
    return elements;
}

So basically if you put the class name TextboxWatermark on any textbox input with the title you like to show as the watermark like this:

<input type="text" class"TextboxWatermark" name="username" id="username" title="Must be at least 6 chars" />

or

<%= Html.TextBox("username", new { @class = "TextboxWatermark", @title = "Must be at least 6 chars" }) %>

What is nice about the second option is that you get the added benefit of getting the View Engine to fill out the value of the textbox if there is an item in ViewData of the ViewData.Model that has a var named 'username'.

So I find this much easier than having to add the control and on each page and for each DOM element i want to attach this behavior to. 

When you want to do the same thing with other controls, you need to know how to call it in JavaScript.  This is the part that is kind of hidden when you are using controls like in WebForms.  If you go to the AjaxControlToolkit Sample Site, and view page source on one of the controls example pages, you will see what JavaScript is generated.  Go to the TextboxWatermark example and then view source from the browser.  You will see 5 of these at the bottom for each control

Sys.Application.initialize(); Sys.Application.add_init(function() { $create(AjaxControlToolkit.TextBoxWatermarkBehavior, {"ClientStateFieldID":"ctl00_SampleContent_TextBoxWatermarkExtender1_ClientState","WatermarkCssClass":"watermarked","WatermarkText":"Type First Name Here","id":"ctl00_SampleContent_TextBoxWatermarkExtender1"}, null, null, $get("ctl00_SampleContent_TextBox1")); });

So this is how you can see how to invoke that control with the arguments, and then of course looking at the source files help you see what else they are doing.  I am already feeling cleaner with the JavaScript since i have just one function that now does it for every Dom element with the class name, "TextboxWatermark".  Here is the function that gets called on pageLoad.  This will attach the behavior for each Dom element.

function AddAllTextboxWatermarks()
{
    var elements = $select('TextboxWatermark');
    for (i=0;i<elements.length;i++)
    {
        AddTextBoxWatermark(elements[i]);
    }
}

function AddTextBoxWatermark(elem)
{
    $create(AjaxControlToolkit.TextBoxWatermarkBehavior, {"WatermarkText":elem.title}, null, null, $get(elem.id));
}

Now the Calendar was just as easy to put in the form.  Here is how I implemented the Calendar:

<%= Html.TextBox("calendar", new { @class = "Calendar" })%>

Now, the calendar was a little tougher to get to work cause of getting the JavaScript just right cause of the amount of files needed.  The Calendar is one of the more complex controls since it uses a popup behavior, animation, timer and threading among others. 

So, that solves simple controls, but what about other controls that need overloads and are not as simple parameter wise.  Well I put all these controls in html helpers also that inject the JavaScript at run time.  I actually started this way, but after using jQuery a little, i really wanted to see if i could implement this using css selectors with the asp.net Ajax framework.  Also it felt like black box controls were creeping back in, but sometimes we need to generate html in c#, so i think it is just about finding the fine line when not to do it and when it is simple and reusable.

Here this an example of the TextboxWatermark as a Html helper:

<%= Html.TextboxWatermark("Enter Username", "username", true) %>

So basically this returns you the input text box,  with the TextboxWatermark behavior attached.  Also it will make sure that the appropriate .js files are in the page along with the html needed to make it work with this particular control.  Now this creates a lot more code in the page just like the controls now do in the existing toolkit, but has its own advantages.  We can create overloads and add additional parameters without having to write JavaScript.  Some people actually don't like to write JavaScript, it is either intimidation or fear of messing up something I guess.  Personally I have used it since the late 90's and is the only language that I have used for 10 years.  Well that and SQL. 

The Calendar control has advantages to being used as a Html helper since we can have several overloads to define format among other parameters that a calendar control can take.  Here is how you set the format:

<%= Html.Calendar("bDay", "MM/dd/yyyy") %>

Also lets say you want a button to invoke the menu, not just clicking in the textbox.

 <%= Html.Calendar("calBtn", "txtDate", "MM/dd/yyyy")%>
 <input type="text" id="txtDate" name="txtDate" />
 <input type="button" id="calBtn" name="calBtn" value="Pick Date" />

Here is a download of a working project with all the necessary files you need to make these controls work either with CSS Selectors or with Html helpers.  I basically created a new mvc web app from scratch using their new templates in Preview 4 that has the membership stuff in it, so that it works with the base starter project that Microsoft provides. 

Download: http://www.jimzimmerman.com/downloads/MvcPreview4AjaxToolkit.zip

Tell me what you think.  I hope you find it useful.  I am leaning towards doing everything with CSS Selectors, but am finding it pretty helpful to use Html helpers also.  I am working on Collapsible Panel and Popup Control next.  I know the Microsoft Ajax team is working on some things with the Toolkit also and look forward to seeing how they integrate it.

Saturday, August 16, 2008 6:27:40 AM UTC #    Comments [1]  |  Trackback

 

Subsonic 2.1 Final is Released#

Yeah!  Subsonic 2.1 Final is released, now time to start comparing it with my version of 2.1 that we have been using in production for months.  The features are so cool and would not even think of switching to Linq if I had to.  Download it here: http://www.codeplex.com/subsonic/Release/ProjectReleases.aspx?ReleaseId=14067

The migrations look very cool and I cant wait to finally start using migrations instead of manually updating SQL by schema comparisons.  Check out a demo here:http://subsonicproject.com/2-1-pakala/subsonic-using-migrations/

Wednesday, July 09, 2008 6:35:42 AM UTC #    Comments [0]  |  Trackback

 

Very Cool Free .NET E-Book#

I just saw a twitter from hanselman on this very cool free e-book on alt.net practices.  It is about 80 pages and very professional.  I would easily pay for this book and am going to have all of my devs in the company read it.

 The Foundation Of Programming Series Free e-book By Karl Seguin

I have just ready the first few chapters so far and would like to read the whole thing in one sitting.  Too bad wife is not game for me to read on my laptop the whole night tonight. :)

I am wondering when I get a kindle if that will be different since I can't "work" on the kindle.

Monday, July 07, 2008 5:33:51 AM UTC #    Comments [0]  |  Trackback

 

TempData not working with SQL Server Session State and ASP.NET MVC Preview 3#

We are extensively using ASP.NET MVC Preview 3 for one of our web projects and we are loving it.  The other day when we deployed our app to our web farm, we realized that we got an error when typing in a wrong password and that our app was not returning the handled error of improper login and the app was blowing up with the error, "Unable to serialize the session state."  When we tracked it down we realized that this only happened when using TempData instead of ViewData. 

So, when redirecting to an action in MVC, you will lose anything you have in ViewData so if you want to carry an error to another action and show it in the next view that is rendered, then you will need to create your own session variables or use the built in TempData which works great except when you are using SQL server for session state instead of in-proc.  Well we have no choice than to use SQL server for session state since we have several web servers on our web farm. 

So, since ASP.NET MVC source code is available on Codeplex, I decided to investigate what class makes up TempData.  I found that TempData uses an internal class called Pair and it is not marked as serializable.  Dare I try to fix it and run with our own version of System.Web.Mvc?  Why not, it is just C#?  the fix was very easy and after adding the serializable attribute to the Pair class.  Pair.cs found in the folder Util inside of the MVC project.

namespace System.Web.Util {
    using System;

    // Generic Pair class.  Overrides Equals() and GetHashCode(), so it can be used as a dictionary key.
    [Serializable] 
    internal sealed class Pair<TFirst, TSecond> {

 

All the tests now passed and most importantly, our site works perfectly.  It was very empowering to add a simple change to the framework and not have to wait for a fix from Microsoft.  I feel so much more comfortable using frameworks that have the source code with them.  That is why we use ASP.NET MVC and Subsonic 2.1.

Friday, June 27, 2008 7:21:40 AM UTC #    Comments [0]  |  Trackback

 

Micro Blogging, Scalability and Twitter#

I have been using Twitter lately and have really gotten into it.  I mostly use it with SMS from my palm treo 700w and have enjoyed the few people I actually follow and find great value in listening to the twitter of these people.  That being said, i have been really curious as to how this system is architected and since i work for a company that is creating a social network for sports among other things, i am fascinated on how to scale a social graph.  The problem seems to be with messaging and more critical the friends feed.  The scale and queries of finding what friends are up to can be a very tricky scalability problem.  I became even more fascinated with this after reading this post: Scaling a Microblogging Service

Also it is refreshing to hear from that actual developers that are creating this system: http://dev.twitter.com/2008/05/youve-got-qs-weve-got-as.html

For any of us that have created a site that actually needs to worry about scale can respect what it feels like when there is slow response or down time from your site.  It is fun and challenging, but sometimes is a thankless job.  For those of you that thrive on the passion of making a real cool service, I commend you and want to give thanks for fixing things that are not so easy to fix, but make the biggest impact system wide.  Those are usually the hardest to find.

Friday, May 30, 2008 9:19:40 AM UTC #    Comments [0]  |  Trackback

 

Moving from ASP.NET Webforms to ASP.NET MVC#

I am currently moving a project from a typical webforms project to the new asp.net mvc framework project.  I am already seeing some huge benefits that I wanted to share with others.  Of course there is no viewstate in asp.net mvc and this has its advantages.  The most significant change is the size of my home page.  the amount of text in the page is down over 40%.  so my home page was 32K and now it is only 18K.  I am noticing even quicker page response times also running locally and on the server.  The page just seems to render faster, especially when hitting the back button.  Also it just feels cleaner without all those controls and I can have 100% control of the html that spits out.  It reminds me of back in the classic asp and PHP days, but without all the pain.  I did not realize how much I missed just writing straight html without controls.  

At first I thought that it would slow me down and that I would have to write more code,  but I think the opposite is true.   I don't have to deal with code behind any more and I can test so much easier now the action that every form calls.  I was able to convert an existing website that had Ajax control toolkit, membership services and several contact forms in about a week.  Not even that if you counted the hours.  Not too bad.  These tutorials really helped me out: http://www.asp.net/LEARN/3.5-extensions-videos/#mvc

We are about ready to go into production with these bits as we see that it is very stable and since we have the source code to the entire framework in our source tree, it feels safe since we can always fix a bug in the framework if we need to.  You can get the source code here: ASP.NET MVC Preview 2 Source Code

Thursday, May 22, 2008 9:47:11 AM UTC #    Comments [0]  |  Trackback

 

Amazon Kindle back in Stock!#

Ever since I have seen the Kindle - wireless reading device , I have wanted to buy one and read the Pragmatic Programmer on it among many other books.  I am trying to figure out the best way to get my wife to agree that this is the thing I need.  I am thinking that maybe reading on it instead of the laptop in bed might be a good reason since this laptop is so bright when she is sleeping sometimes.  You know when you really want something that you have looked at it so many times, trying to find the one reason why you shouldn't get it, but you keep reading good review after good review.  Maybe I can win one at a conference or if I visualize that it is in my hand, it will just magically appear.  That would not be the first time that has happened.  It did with my Zune 80.

Monday, May 05, 2008 11:55:26 AM UTC #    Comments [0]  |  Trackback

 

JavaScript to Managed Code in Silverlight 2 Beta 1#

I had to solve an interesting problem the other day for our new Silverlight 2 chat app for our site.  People were closing the browser window and not clicking the leave chat button which clears out their chat session.  So we needed to find a way to close out their chat session.  There are several ways to solve this problem, write a windows service to clear out stale sessions among many others, but the real solution was to figure out a way to have a Silverlight function get called from JavaScript when they close the browser window.

So the first problem to solve is to catch the browser window close event in JavaScript.  Here is the the script you need to do just that on all 3 browsers, Firefox, IE and Safari.

<script type='text/javascript'>
        
        window.onbeforeunload = function() {
            var slCtl = document.getElementById("Xaml1"); 
            slCtl.Content.mySLapp.StopChatting();
            alert("You have been logged out");
        }

    </script>

The Xaml1 control is referencing the asp:Silverlight control that is on the page.  the slCtl.Content.mySLapp.StopChatting();  call is calling a method on my c# class in the silverlight project.  In order to make this work you will need to do two things in your silverlight project.  The first thing you need to do is to register managed code for client script access.  In the Application_Startup method in App.xaml.cs, call the RegisterScriptableObject() method on the HtmlPage object and pass in your type that you want to reference in your script.  Here is a sample of how to do it.

 
using System.Windows.Browser;

namespace Chat
{
    public partial class App : Application
    {

        public App()
        {
            this.Startup += this.Application_Startup;
            this.Exit += this.Application_Exit;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            // Load the main control
            this.RootVisual = new Page();

            //Setup some scriptable managed types for access from Javascript.
            ScriptableType st = new ScriptableType(); 
            HtmlPage.RegisterScriptableObject("mySLapp", st);

        }

        private void Application_Exit(object sender, EventArgs e)
        {

        }
        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {

        }
    }
}
Now we need to create the ScriptableType class and add the ScriptableMemberAttribute 
attribute, which is required in order to expose the members to client script.
using System.Windows.Browser;

namespace Chat
{
    public class ScriptableType
    {
        public ServiceHandler svc;

        [ScriptableMember()]
        public void StopChatting()
        {
            svc = ServiceHandler.Instance;
            svc.StopChatting();
        }
    }
}
You can also return a type string if you want and then alert that string that is returned in JavaScript.
It really is a very powerful feature and I am very excited to use this power in many other ways. Happy coding!
Wednesday, April 30, 2008 11:12:40 AM UTC #    Comments [0]  |  Trackback

 

 

All content © 2008, Jim Zimmerman
Book
New Book
Links to me
On this page
Sponsors
Calendar
<August 2008>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456
Archives
Tags
Blogroll OPML
Technorati
Favorite Links
Disclaimer

Powered by: newtelligence dasBlog 1.9.6264.0

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Send mail to the author(s) E-mail