Solving the “A potentially dangerous Request.Form value was detected….” in ASP.NET MVC

By at December 30, 2010 15:57
Filed Under:

Oftentimes an MVC application needs to POST text back that a user has entered into a text field or textarea. In a project I am working on I am using the TinyMCE WYSIWYG text editor to allow users to write articles. The editor allows for HTML tags such as <p>, <strong>, <em>, etc., and when submitting the form I have run across the infamous, “A potentially dangerous Request.Form value was detected” error. So, how do you get around this? You want the user to be able to use some HTML, but you need to secure your site as well from scripting attacks.

Enter the [ValidateInput(false)] attribute.

Adding this attribute to each of the ActionResults where you are expecting HTML tags to come in, will allow the Controller to continue with the action. This will work most of the time but is not exactly bulletproof for protecting your site.

By doing a string.Replace() on the incoming content, and checking for suspicious and/or malicious code, you can secure your site a bit more.

   1: [ValidateInput(false)]
   2: [HttpPost]
   3: public ActionResult Create(Article article, FormCollection collection)
   4: {
   5:   var author = HttpContext.User.Identity.Name;
   6:   var member = _appHelpers.GetAuthenticatedMember(author);
   7:   article.ArticleContent = 
   8:       article.ArticleContent.Replace("<script", "[script")
   9:       .Replace("</script>", "[/script]");
  10:   _repo.Create(article);
  11:   return RedirectToAction("Edit", new {articleId = article.Id});
  12: }

Lines 8 and 9 in the above code will replace “<script>” tags with innocuous [script strings making sure no javascript can run in the code which is submitted. You can also continue along this line to remove any SQL injection attack strings as well.

A nice little method to put in your tool belt. Be sure to use it on your Edit Actions as well.

Happy Programming from ComponentOne

James

POSTing and GETting with jQuery and MVC

By at December 28, 2010 14:30
Filed Under:

The jQuery library has an extensive set of AJAX functions which make it very easy to handle website functionality with all the Ajaxy goodness you’ve come to expect. However there are some gotcha’s when working with MVC and I thought I’d take some time to talk about them.

The first thing to remember is to decorate your Actions with the appropriate Http verbs, either [HttpPost] or [HttpGet]. By default MVC 2 only allows [HttpPost] requests when requesting a Json response. Phil Haack has a great article on this at http://haacked.com/archive/2009/06/25/json-hijacking.aspx.

In a project I am working on I want users to be able to add other users as friends, see if their friend is online, and if necessary, delete a friend. This jQuery function allows a user to add a friend:

   1: function acceptFriend(friendId) {
   2:     var url = "/Member/AcceptFriendRequest/";
   3:     var data = "friendId=" + friendId;
   4:     $.post(url, data,
   5:         function (json) {
   6:             if (json == "success") {
   7:                 //add the div to the My Friends section
   8:                 addNewFriendToList(friendId);
   9:             } else {
  10:  
  11:             }
  12:         }, 'json');
  13: }

You can see here that I am POSTing the data back to the server by defining the url, and any data that needs to be sent as well (lines 2 and 3). Then, depending on the response, add the friend to a friend list. I don’t use an ActionResult but instead use a JsonResult in the Member controller.

   1: [HttpPost]
   2: public JsonResult AcceptFriendRequest(int friendId)
   3: {
   4:   var status = "success";
   5:   try
   6:   {
   7:     var member = _appHelpers.GetAuthenticatedMember(User.Identity.Name);
   8:     var memberId = member.Id;
   9:     var memberFriend = (from mf in _db.MemberFriends
  10:                 where mf.MemberId.Equals(memberId) 
  11:                 && mf.FriendId.Equals(friendId)
  12:                 select mf).FirstOrDefault();
  13:      if(memberFriend != null)
  14:      {
  15:        memberFriend.Approved = true;
  16:        _db.SaveChanges();
  17:      }
  18:    }
  19:    catch(Exception ex)
  20:    {
  21:       status = "false";
  22:    }
  23:    return Json(status);
  24: }

One thing I have discovered that for POST actions you don’t need the [HttpPost] attribute, but I put it in there for readability. The code above is pretty straightforward and not difficult to understand. What caused me a few hours of head scratching was when I was trying to do a GET and find out if a user was online. Two things were standing in my way, and I realized I *needed* to use the [HttpGet] attribute, and override the JsonResult’s default of not allowing GETs. This jQuery checks to see if a user is online.

   1: $.ajax({
   2:   url: "/Member/UserIsOnline/" + friend, //friend is an (int) id defined earlier
   3:   type: "GET",
   4:   success: function (result) {
   5:       if (result == "true") {
   6:          $(friendElement).removeClass("friendOffline").addClass("friendOnline");
   7:       } else {
   8:          $(friendElement).removeClass("friendOnline").addClass("friendOffline");
   9:       }      
  10:    }
  11:  });

The JsonResult in the controller is decorated with [HttpGet]

   1: [HttpGet]
   2: public JsonResult UserIsOnline(int id)
   3: {
   4:  var member = _appHelpers.GetMemberById(id);
   5:  bool isOnline;
   6:  try
   7:  {
   8:    MembershipUserCollection users = Membership.GetAllUsers();
   9:    MembershipUser user = users[member.Email];
  10:    isOnline = user.IsOnline;
  11:  }
  12:  catch (Exception ex)
  13:  {
  14:    isOnline = false;
  15:  }
  16:  return Json(isOnline, JsonRequestBehavior.AllowGet);
  17: }

If you don’t add the JsonRequestBehavior.AllowGet parameter you will get the following error when attempting to run you code:

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.

Once you get these gotchas out of the way, you’re on your way.

Happy Programming from ComponentOne

James

Uploading photos with MVC

By James at December 22, 2010 13:49
Filed Under:

There are many articles online talking about MVC, but not many showing how to upload files. In a project I’m working on I need to have my users upload photographs and wanted them to be able to preview the photo before submitting it. Here’s a screen shot of what I’m talking about.

7318.image_677BC867

The application allows the user to select a photo, which is then previewed. The user can then add a caption and description of the photo. During this first round the Save button is bound to the following jQuery script:

   1: function uploadMemberPhoto(elem) {
   2:     var $elem = $(elem);    
   3:     $("div.memberPhotoUploader").fadeIn(500);
   4:     var $form = $elem.parents("form");
   5:     $form.attr("action", "/MemberPhotos/Uploaded");
   6:     $elem.fadeOut(500, function () { $form[0].submit(); });
   7: }

which sets the action of the form to “/MemberPhotos/Uploaded”, then submits the form. The Controller action “Uploaded” handles the processing of the image.

   1: public ActionResult Uploaded(HttpPostedFileBase file, FormCollection formCollection)
   2: {
   3:   var memberPhoto = _photoHelpers.UploadMemberPhoto(file, formCollection);  
   4:   return View("UploadedPhoto");
   5: }

_photoHelpers is a helper class which does the processing of the image

   1: public MemberPhoto UploadMemberPhoto(HttpPostedFileBase file, FormCollection collection)
   2: {
   3:   var memberPhoto = new MemberPhoto();
   4:   try
   5:   {
   6:      if(file.ContentLength > 0)
   7:      {
   8:       var member = _repo.Get<Member>(int.Parse(collection["memberId"]));
   9:       var photoCaption = collection["memberPhotoCaption"];
  10:       var photoDescription = collection["memberPhotoDescription"];                    
  11:       var serverPath = HttpContext.Current.Server.MapPath(
  12:              ConfigurationManager.AppSettings["memberAvatarPath"]);
  13:       var memberFolder = GetMemberImageFolder(member);
  14:       var imagePath = serverPath + memberFolder;
  15:  
  16:       if (!Directory.Exists(imagePath))
  17:           Directory.CreateDirectory(imagePath);
  18:  
  19:       bool success = ImageHelpers.ProcessMemberPhotoUpload(file, imagePath);
  20:       if(success) // insert the record
  21:       {
  22:           memberPhoto.MemberId = member.Id;
  23:           memberPhoto.PhotoUrl = file.FileName;
  24:           memberPhoto.PhotoCaption = photoCaption;
  25:           memberPhoto.PhotoDescription = photoDescription;
  26:           memberPhoto.IsApproved = false;
  27:           memberPhoto.IsVisible = true;
  28:           memberPhoto.CreateBy = member.Email;
  29:           memberPhoto.CreateDate = DateTime.Now;
  30:           memberPhoto.ModifyBy = member.Email;
  31:           memberPhoto.ModifyDate = DateTime.Now;
  32:           memberPhoto.Mode = ImageHelpers.ImageMode(file);
  33:           _repo.Create(memberPhoto);
  34:        }
  35:     }
  36:  }
  37:   catch (Exception ex)
  38:   {
  39:     memberPhoto = null;
  40:   }
  41:   return memberPhoto;
  42: }
   1: public bool ProcessMemberPhotoUpload(HttpPostedFileBase img, string fPath)
   2: {
   3:   fPath = fPath.Replace("\\\\", "\\");
   4:   var resizedImage = ResizeImage(img, new Size(640, 480));
   5:   var status = SaveImage(resizedImage, fPath, img.FileName);
   6:  
   7:   var thumbNail = ResizeImage(img, new Size(102, 77));
   8:   status = SaveImage(thumbNail, fPath, "thmb_" + img.FileName);
   9:  
  10:   var largeThumb = ResizeImage(img, new Size(400, 600));
  11:   status = SaveImage(largeThumb, fPath, "lgthmb_" + img.FileName);
  12:   return status;
  13: }

The rest of the methods used in the helper class are here

   1: private static Image ResizeImage(HttpPostedFileBase img, Size size)
   2: {
   3:   var oImage = Image.FromStream(img.InputStream);
   4:   var sWidth = oImage.Width;
   5:   var sHeight = oImage.Height;
   6:             
   7:   if(size.Width >= oImage.Width && size.Height >= oImage.Height)
   8:       return (Image) oImage;
   9:  
  10:   float nPercent = 0;
  11:   float nPercentW = 0;
  12:   float nPercentH = 0;
  13:  
  14:   nPercentW = ((float) size.Width/(float) sWidth);
  15:   nPercentH = ((float) size.Height/(float) sHeight);
  16:  
  17:   if (nPercentH < nPercentW)
  18:      nPercent = nPercentH;
  19:   else
  20:      nPercent = nPercentW;
  21:  
  22:   int dWidth = (int) (sWidth*nPercent);
  23:   int dHeight = (int) (sHeight*nPercent);
  24:  
  25:   Bitmap b = new Bitmap(dWidth, dHeight);
  26:   Graphics g = Graphics.FromImage((Image) b);
  27:   g.InterpolationMode = InterpolationMode.HighQualityBicubic;
  28:   g.DrawImage(oImage, 0, 0, dWidth, dHeight);
  29:   g.Dispose();
  30:   return (Image) b;
  31:  }
  32:  
  33:  private static bool SaveImage(Image img, string savePath, string fileName)
  34:  {
  35:    var status = true;
  36:    try
  37:    {
  38:       var newPath = new StringBuilder(savePath).Append(fileName);
  39:       File.Delete(newPath.ToString());
  40:       img.Save(newPath.ToString(), img.RawFormat);
  41:    }
  42:    catch (Exception)
  43:    {
  44:      status = false;
  45:    }
  46:    return status;
  47: }
  48:  
  49: public string ImageMode(HttpPostedFileBase img)
  50: {
  51:   var oImage = Image.FromStream(img.InputStream);
  52:   var mode = "landscape";
  53:   if (oImage.Width < oImage.Height) mode = "portrait";
  54:      oImage.Dispose();
  55:   return mode;
  56: }

In this particular application, all photos uploaded need to be approved, so after the photo is uploaded, the page refreshes, keeping the original form action of “/MemberPhotos/UpdatePhoto”

8688.image_61FD31F6

   1: public ActionResult UpdatePhoto(MemberPhoto photo)
   2: {
   3:    photo.ModifyBy = User.Identity.Name;
   4:    photo.ModifyDate = DateTime.Now;
   5:    _repo.Edit(photo);
   6: }

You may be wondering how the image is previewed. I found this article at, http: //weblogs.asp.net/imranbaloch/archive/2010/04/03/image-preview-in-asp-net-mvc.aspx and modified it a bit for my needs. This bit of javascript works like a champ.

   1: function ChangeImage(fileId, imageId) {
   2:     $("div.memberPhotoUploader").fadeIn(500);
   3:     $("#form1").ajaxSubmit({ success: function (responseText) {
   4:         if (isImage(responseText)) {
   5:             var d = new Date();
   6:             $(imageId)[0].src = "/ImagePreview/ImageLoad?a=" + d.getTime();
   7:             $(imageId).show();
   8:             $("input#uploadButton").removeClass("btnSaveDisabled")
   9:               .addClass("btnSaveEnabled").removeAttr("disabled").click(function () { 
  10:                 uploadMemberPhoto(this); 
  11:           }); ;
  12:         } else {
  13:             $(imageId).hide();
  14:             $("div.imageTypeNotice").show();
  15:         }
  16:         $("div.memberPhotoUploader").fadeOut(500);
  17:     }
  18:     });
  19: }

Happy programming from ComponentOne

James

Easy control styling with Foxy

By James at December 20, 2010 19:28
Filed Under: Foxy, Visual Style Designer, Design

Using third party controls like ComponentOne’s tools makes building your websites faster and easier. And, with all the themes that the C1 tools have, chances are you can find one which blends nicely. But if you can’t then what do you do? You really don’t want to go digging through all the CSS and graphics files to make a few changes, nor do you want to make your site match the theme you’ve chosen. Well fret no more, along comes Foxy.

5417.image_51FE523C

C1’s Foxy allows you to edit a theme from Studio for ASP.NET, or even create your own theme to use with the Studio for ASP.NET components. You can choose to edit just a few controls or the entire theme’s suite, drilling down as far as you want to. More than likely all you really need to do is just change the colors slightly, and this is where Foxy really makes it easy for you by allowing you to change the HLS properties of the theme. Here’s how to do it.

1. Open Foxy. It will be in your Start Menu at ComponentOne, Studio for ASP.NET AJAX, Style Designer, Foxy for ASP.NET

7571.image_49DF5247

2. I have found that “ArticFox” is the best one to modify via the Colorize feature as it is the most bland so all the elements will look good when colorized. From the VisualStyles window, select a ArticFox and drag it down to the Custom VisualStyles window

8231.image_155E7FFF

3. Expand the ArcticFox-Custom1 node, then double-click one of the controls. I am going to continue this using the C1Calendar. If you plan to only use a few controls in your project, select, then delete, the controls in this panel you won’t be using. Otherwise when you import into your project all of them will go across as well.

8463.image_251E1503

4. Double-clicking the control, opens the control in the Foxy designer surface, showing the hierarchy of the control’s elements, the control itself and the CSS for the control

2045.SNAGHTMLde2d4c4_1843BEE5

5. For now, just select the C1Calendar node in the upper left corner of the screen, then click on the Colorize button in the tool bar towards the upper right.

0451.image_1475F448

6. This brings up the Hue/Saturation dialog window

1057.SNAGHTMLde65d16_250DEF36

7. Click on the Colorize check box. You can then choose a color, or make changes to the current color with the Hue, Saturation and Lightness sliders. I’ve selected the teal color, (4 over, 3 down).

3005.image_716582D7

8. In the Hue/Saturation dialog window, start playing with the sliders to colorize the theme. You will see the changes in real time.

3201.image26_7A720E58

9. Setting the values to Hue: 124, Saturation: 35, Lightness: –46 makes a nice Olive color. Click on Apply and you will see your changes in the designer pane.

3288.image_2D619EC0

What’s really nice about the Colorize option is that it takes care of the graphics as well, giving them the same colors as the HTML elements.

The C1Calendar control, as most of the other C1 controls are set to inherit the font family of your own style sheet. However they may be times when you want the control to have a bit different font – a little bigger, bold perhaps, maybe a different color – and this is another area where Foxy makes it easy.

1. In the left hand control panel, select the “Control” node, just after the parent node, “C1Calendar”

2. In the Ribbon Font bar, select a font family from the drop down. The changes will be made in real time so you can play around with the different settings to get just the look you want.

5672.image_302753B3

When you get all your changes made, click on the Save button. So, we made this nice theme for our calendar, now how do we get it into our project?

1. In your ASP.NET Web Application Solution Explorer, right click on the project name and select Add, New Folder. Name the new folder, “VisualStyles”, then right click on the new folder and select Add, New Folder, naming this folder the name of the theme you just created. On this new folder right click again and select Add, New Folder, naming this one C1Calendar.

5556.image_039E23CD

2. Add the custom css file you created above by right clicking on C1Calendar then selecting Add, Existing Item. Navigate to where Foxy saves your files on your computer, typically “C:\Users\<UserName>\Documents\C1FoxyVSD\<Custom Theme Name>\<Control Name>. In this case the folder I am looking for is “C:\Users\James\Documents\C1FoxyVSD\ArcticFox-Custom1\C1Calendar\styles.css”. Select the file, then click on Add.

3. We need to add the images for the Calendar control as well, so right click on the C1Calendar folder in the Solution Explorer and select Add, New Folder, naming it “Images”. Right click on the new “Images” folder and select Add, Existing Item, then navigate to the same folder as you went to in Step 2 above, “C:\Users\James\Documents\C1FoxyVSD\ArcticFox-Custom1\C1Calendar\Images”. Select the two files, “calendar.png” and “calendar-repeater.png”, then click on Add.

4. Add a C1 Calendar control to your page, by dragging it from the Toolbox to the aspx page in Visual Studio, then click on the Design tab in the lower left corner of Visual Studio.

5. Click the Calendar control’s Task button to bring up the Task dialog

4774.image_33E4F883

6. Change the VisualStylePath to ~/VisualStyles, this is the folder you created in step 1

7. Uncheck the UseEmbeddedVisualStyles check box

8. Click in the VisualStyle drop down and your Custom style will be present. Select it

6136.image_2AA8BD42

9. Run your application and you will see the calendar rendered with the new Visual Style

2806.before_6855A4FE 7840.after_0653B2F3
Before styling with Foxy After styling with Foxy

In this article we talked about how easy it is to use ComponentOne’s controls. We also talked about how using the Visual Style designer, Foxy, can make it really simple to make small changes to the controls to add your own colors and emphasis. Foxy is a really great tool, that can make your development even more fun and productive.

Happy Programming,

James

jQuery and MVC–Part 4, now with Wijmo!

By James at December 17, 2010 11:04
Filed Under: JavaScript, jQuery, jQuery Plugins, Wijmo

In part three of this series I talked about how to extend jQuery with plugins, went through the steps of writing a plugin, and then demonstrated how to use it in a standard HTML page. I showed you a popular Table Sorter plugin and showed how to initialize it with different options. In this last article I will show you one more plugin, the Wijmo Grid, and how easy it easy to implement it’s different options and features. I will also show you some of the cool things that Wijmo can do to help spruce up your web forms and pages.

Going back to the Student Course Admin form I’ve been using for these articles, I am generating a table of student data in an ASP.NET MVC app.

7563.image_281CC156

One thing I did add since the last article was the ability to filter the students by their first or last name.

4186.image_2BDA6626

3666.image_43919D8C

This was done by adding some JavaScript and an Ajax call which gets a new set of data from the server, then replaces the original table with the new table.

   1: function getStudentsByName(elem) {
   2:     $("img.ajaxLoaderFName").fadeOut(500);
   3:     $("img.ajaxLoaderLName").fadeOut(500);
   4:     var $elem = $(elem);
   5:     var url = "";
   6:     var ajaxLoader;
   7:     if ($elem.attr("id") == "txtFilterFName") {
   8:         url = "/Home/GetStudentsByFirstName/" + $elem.val();
   9:         ajaxLoader = $("img.ajaxLoaderFName");
  10:     }
  11:     if ($elem.attr("id") == "txtFilterLName") {
  12:         url = "/Home/GetStudentsByLastName/" + $elem.val();
  13:         ajaxLoader = $("img.ajaxLoaderLName");
  14:     }
  15:     
  16:     ajaxLoader.fadeIn(500);
  17:     $.ajax({
  18:         url: url,
  19:         type: "GET",
  20:         success: function (result) {
  21:             var holder = $("table.studentTable").parent("div.row");
  22:             $("table.studentTable").remove();
  23:             holder.html(result);
  24:             ajaxLoader.fadeOut(500);
  25:             $("div.chkGraphic").graphicCheckBox();
  26:         }
  27:     });
  28: }

Pretty standard stuff by now, but it can be made a whole lot better by using Wijmo. Let’s see how to do that.

Wijmo

Wijmo is a new product, complete kit of over 30 jQuery UI Widgets. It is a mixture of jQuery, CSS3, SVG, and HTML5. You can download it at www.wijmo.com.

The Wijmo grid has 20 different options that you can mix and match to make your grid look and behave how you would like. Detailed information about these options can be found at http://wijmo.com/wiki/index.php/Grid#ui.wijgrid_Options. For this demo, I am going to setup the grid with the following options: allowSorting, allowColumnSizing, allowPaging, and setting the page size to 10 rows.

As I mentioned before, when adding the references to your JavaScript files, the order of each reference is very important. After you download Wijmo, there will be several JavaScript files which will need to be included in your page.

   1: <script type="text/javascript" 
   2:   src="[Path]/Wijmo-Open/development-bundle/external/
   3:   jquery-1.4.3.min.js"></script>
   4:  
   5: <script type="text/javascript" 
   6:   src="[Path]/Wijmo-Open/development-bundle/external/
   7:   jquery-ui-1.8.6.custom.min.js"></script>
   8:  
   9: <script type="text/javascript" 
  10:   src="[Path]/Wijmo-Open/development-bundle/external/
  11:   jquery.bgiframe-2.1.3-pre.js"></script>
  12:  
  13: <script type="text/javascript" 
  14:   src="[Path]/Wijmo-Open/development-bundle/external/
  15:   jquery.glob.min.js"></script>
  16:  
  17: <script type="text/javascript" 
  18:   src="[Path]/Wijmo-Complete/development-bundle/external/
  19:   jquery.mousewheel.min.js"></script>
  20:  
  21: <script type="text/javascript" 
  22:   src="[Path]/Wijmo-Complete/development-bundle/external/
  23:   jquery.tmpl.min.js"></script>
  24:  
  25: <script type="text/javascript" 
  26:   src="[PathToJavaScript]/Wijmo-Complete/development-bundle/external/
  27:   raphael.js"></script>
  28:  
  29: <script type="text/javascript" 
  30:   src="[PathToJavaScript]/Wijmo-Open/js/
  31:   jquery.wijmo-open.1.0.0.min.js"></script>
  32:  
  33: <script type="text/javascript" 
  34:   src="[PathToJavaScript]/Wijmo-Complete/js/
  35:   jquery.wijmo-complete.1.0.0.min.js"></script>

You will also need to reference the Wijmo style sheets as well.

   1: <link href=”[Path]/Wijmo-Complete/development-bundle/themes/
   2:   ui-lightness/jquery-ui-1.8.4.custom.css" rel=”stylesheet
   3:   type=”text/css/>
   4:  
   5: <link href=”[Path]/Wijmo-Open/css/jquery.wijmo-open.1.0.0.css" 
   6:   rel=”stylesheettype=”text/css/>
   7:  
   8: <link href=”[Path]/Wijmo-Complete/css/jquery.wijmo-complete.1.0.0.css" 
   9:   rel=”stylesheettype=”text/css/>

Initializing the Wijmo grid is done the same way you do other things in jQuery, by getting an element in the page, in this case the table with an ID of “studentTable”, then adding the jQuery plugin to the element.

   1: $("#studentTable").parent().wijgrid({ 
   2:     allowSorting: true, 
   3:     allowColSizing: true, 
   4:     allowPaging: true, 
   5:     pageSize: 10 
   6: });

Here is the result.

0027.image_27A06894

As you can see the graphical check buttons I talked about in the last article are still there, and the grid has a nifty pager at the bottom.

The allowSorting option adds sorting capability on each column as seen here.

4578.image_52985699

While the “allowColSizing” lets you adjust the widths of each column to better view your data.

1300.image_1A9662B6

Another great option with the Wijmo grid is to allow editing to your data. In the jQuery to initialize the Wijmo grid, add another option, allowEditing:true.

   1: $("#studentTable").wijgrid({ 
   2:     allowSorting: true, 
   3:     allowColSizing: true, 
   4:     allowPaging: true, 
   5:     pageSize: 10, 
   6:     allowEditing: true 
   7: });

When the grid is rendered, each table cell will now become editable. All you have to do is click in the cell and start making any changes you need. The Wijmo Grid exposes events so you can handle the changed data however you prefer to.

There are 15 events total in the Wijmo Grid, and details on each of them are at http://wijmo.com/wiki/index.php/Grid#ui.wijgrid_Events. The Wijmo grid is very feature rich and I would highly recommend you play around with it.

Other Wijmo goodies

No more do you have to deal with boring old form elements on your page. Wijmo has decorators for Radio Buttons, Checkboxes, Drop Downs and Text fields. Adding these decorators is as easy as adding an additional jQuery call to your selected element.

So, by adding the following to my text fields which filter by student name.

   1: $("input#txtFilterFName").focus(function () { 
   2:     $("input#txtFilterLName").val(""); }).keyup(function () { 
   3:     getStudentsByName(this); }).wijtextboxdecorator();
   4:  
   5: $("#chkPaging").wijcheckboxdecorator();
   6:     $("#txtPageSize").wijtextboxdecorator();
   7:     $("input[type=radio]").wijradiobuttondecorator();

I get these spiffy looking text fields and form elements.

7484.image_52F463C1

One thing you may have noticed is that the grid and the form elements all have the same theme. This is because of the jQuery UI theming that is built into Wijmo. If you don’t like how the elements look you can create your own themes with the jQuery UI Theme Roller at http://jqueryui.com/themeroller/. When you get your theme just how you want it to, all it takes is a download, and referencing your theme’s particular style sheet in your page.

7026.image_43051EFD

   1: <link href="[Path]/Content/ui-lightness/jquery-ui-1.8.4.custom.css"
   2:     rel="stylesheet" type="text/css" />

In this article we talked more about jQuery plugins, the Wijmo gallery of widgets and how they can be used to create dynamic and very professional looking web applications. I hope you have enjoyed this series and have learned a few tricks. And as always, I would love to read your comments on my blog.

Happy Programming,

James

New Mexico .NET Users Group

By James at December 06, 2010 18:58
Filed Under: user groups, community

Last Thursday, December 12, I had the opportunity to go to Albuquerque, New Mexico and present at the New Mexico .NET Users Group. My flights were uneventful, checking into the hotel a breeze, and I got a free upgrade on the rental car, all that was left was to meet the group and give them my presentation, “ASP.NET MVC, jQuery, Ajax, EF and some other groovy stuff thrown in”. After the typical networking between members, the meeting started promptly at 7:00 pm, with some announcements by the president Tom Murdock. I was expecting a typical length meeting, but had been told just prior that their meetings usually go to 8:30 pm. Uh-oh I think, “two and half hours in 75 minutes”. Knowing that I would have less time I sneakily started my presentation a bit early, asking the usual questions I start off with – number of web and windows developers, C# vs. VB, who does their own database admin, etc.

My presentation turned into more of a lightning talk and actually it turned out pretty well. There was still time for audience questions and comments, I was focused on the code and concept so there wasn’t any time for tangents, and even had a little back and forth with one young kid who kept teasing me about not using PHP. I was able to tease him back and the whole presentation turned out very enjoyable. And as it turned out, I was able to go until 9:00 pm.

The attendees treat each other like family members, which was great to see. One of the things I noticed, and bumped up my ego several notches was to see many of the attendees taking notes on what I said. I added several more twitter followers, and three people actually commented on my presentation at www.speakerrate.com. Tom has grown a great group and should be congratulated for all his accomplishments. Best of all, they invited me back for another presentation.

All in all, one of the best visits I’ve had!

Here’s some pictures

4380.IMG_2511_277FED2C 0676.IMG_2512_248A8879
5621.IMG_2513_687E46C3 1207.IMG_2514_30E885D5
1374.IMG_2515_75487714  
Tom Murdock – right and ComponentOne Studio winner, James Archuleta  

Happy Programming

James

About the author

James James is a five time and current Microsoft MVP in Client App Development, a Telerik Insider, a past Director on the INETA North America Board, a husband and dad, and has been developing software since the early days of Laser Discs and HyperCard stacks. As the Founder and President of the Inland Empire .NET User's Group, he has fondly watched it grow from a twice-a-month, early Saturday morning group of five in 2003, to a robust and rambunctious gathering of all types and sizes of .NET developers.

James loves to dig deep into the latest cutting edge technologies - sometimes with spectacular disasters - and spread the word about the latest and greatest bits, getting people excited about developing web sites and applications on the .NET platform, and using the best tools for the job. He tries to blog as often as he can, but usually gets distracted by EF, LINQ, MVC, ASP, SQL, XML, and most other types of acronyms. To keep calm James plays a mean Djembe and tries to practice his violin. You can follow him on twitter at @latringo.

And as usual, the comments, suggestions, writings and rants are my own, and really shouldn't reflect the opinions of my employer. That is, unless it really does.

James Twitter Feed

Recent Comments

Comment RSS

Month List