Sunday, June 13, 2010

Using T4MVC in ASP.NET MVC2

For the last 2 months, I have been using T4MVC for my MVC2 projects - and it is awesome! Previously, to provide strongly typed view name/path, I have to create a helper class that list all of my view names and location, so when I refer to them I can just type:

<% Html.RenderPartial(ViewLocations.MyCustomview);%>
This is handy, but every time I create new view or rename it, I have to be diligent in renaming it in my helper class. With T4MVC, all this are done automatically!

You can get T4MVC template via MVC Contrib project in Codeplex. How to use it - after the jump.

To use it, you will need to follow these easy steps:

  1. Download T4MVC (consisting of 2 files: T4MVC.tt and T4MVC.settings.t4)
  2. Put the files at the root of your ASP.NET MVC project
  3. That's it basically. If you need to regenerate code, right click on the T4MVC.tt file and click "Run Custom Code"
Here are some of the benefits of using T4MVC template that I heavily depending upon now. For more examples, click here for T4MVC docs on Codeplex.

View Name Constants
Instead of writing this:
 <% Html.RenderPartial("~/Views/MyController/MyCustomView.ascx");%>
I can now write:
 
<% Html.RenderPartial(MVC.MyController.Views.MyCustomView);%>
  
It even works if you have deeper folder structure, so instead of:
  
<% Html.RenderPartial("~/Views/MyController/Controls/MyCustomView.ascx);%>
  
Now I can do this:
 
<% Html.RenderPartial(MVC.MyController.Views.Controls.MyCustomView);%>
  
Also wonderfully works with Area:
 
<% Html.RenderPartial(MVC.MyArea.MyController.Views.Controls.MyCustomView);%>
  
This obviously also works from inside the controller,so instead of:
return View("~/Area/MyArea/Views/Controls/MyCustomView.ascx");
Now:
return View(MVC.MyArea.MyController.Views.Controls.MyCustomView);


Controller Actions
Previously in MVC you have write something like these:
<% =Html.ActionLink("Click here", "MyAction", "MyController")%>

<% =Html.ActionLink("Next Page", "GoToPage", "MyController", new { id = 1, page = 2, active = true })%>

Now with T4MVC magic, they become:
<% =Html.ActionLink("Click here", MVC.MyController.MyAction())%>

<% =Html.ActionLink("Next Page", MVC.MyController.GoToPage(1, 2, active))%>

Or if you have to add additional parameters that are not in the signature of the action:
<% =Html.ActionLink("Click here", MVC.MyController.MyAction().AddRoutevalue("param1", "John"))%>

<% =Html.ActionLink("Next Page", MVC.MyController.GoToPage(1, 2, active).AddRouteValues(new { sortField = "Name", sortDirection = "asc" }))%>


Using it in BeginForm
<%
using (Html.BeginForm(MVC.MyController.Edit(Model.Id), FormMethod.Post)) {
...
}

%>
There are much more usage of T4MVC that will make your MVC coding much more easier. What I have shown you are just the stuff I used the most. I recommend you to check out the docs in Codeplex for more examples.
-- read more and comment ...

Wednesday, June 9, 2010

jQuery 1.4.x Ajax traditional option

I have a very simple jQuery code that basically sends an array of integer back to my ASP.NET MVC Controller class.

 
$.post ("/MyController/MyAction", { myArray: ids });
My controller action:
 
public void MyAction (int[] myArray) {
   // do stuff here ...
}
But upon upgrading to jQuery 1.4.x, it does not work anymore. The param "myArray" in MyAction is always null.

During debugging, I found out that somehow it sent the post data as "myArray[]" instead of "myArray". Of course, you cannot name a parameter name with brackets in C# so simply renaming the parameter name in MyAction won't work.

After some readings, it turns out that this is a change in the jQuery 1.4 release - it changes the way it does param serialization. But, jQuery also provides a new flag in $.ajax to override the default behavior (and go back to use the old way of param serialization): the "traditional" option in $.ajax. So here is my revised code:
 
$.ajax({
   type: 'POST',
   url: "/MyController/MyAction",
   data: { myArray: ids },
   traditional: true
});
You can read more about the new param serialization here and here (under "Nested param serialization" section).
-- read more and comment ...

ASP.NET MVC2 Editor Template for DateTime with jQuery datepicker

Equipping a textbox with datepicker using jQuery is super easy. Once all the jQuery javascript files are referenced, all you need to do is this:

 
$(document).ready(function () {
    $("#myTextbox").datepicker({
        showOn: 'focus',
        changeMonth: true,
        changeYear: true
    });
});
So now, with EditorTemplate in ASP.NET MVC2, this gets easier. So basically I can override the default EditorTemplate for System.DateTime class (which just returns a regular text-box). Once the EditorTemplate is overridden, every time there is a DateTime in edit mode, it will be displayed using my template - which display a smaller text-box and pops up a datepicker once is focus.

Here is my EditorTemplate, located at /Views/Shared/EditorTemplates/DateTime.ascx:
 
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.DateTime?>" %>
<%=Html.TextBox("", (Model.HasValue ? Model.Value.ToString("MM/dd/yyyy") : DateTime.Today.ToShortDateString()), new { @class = "UseDatePicker date-text-box" })%>
Now, to declare the datepicker binding once and for all, I moved it to my master page - and instead of using the "id" of the element, use the class as the selector:
 
$(document).ready(function () {
    $(".UseDatePicker").live('click', function () {
        $(this).datepicker('destroy').datepicker({
            showOn: 'focus',
            changeMonth: true,
            changeYear: true
        }).focus();
    });
});
Now adjust the CSS for width of the text-box and other styles:
 
.date-text-box { width: 6em; }
UPDATE: Get the fully working sample project here.

Additional readings:
-- read more and comment ...

Monday, June 7, 2010

VS 2010 Coded UI Test

Last year, ASP.NET Test team release ASP.NET Lightweight Automation Framework and I blogged about it here. With VS 2010 Ultimate, you now can use "Coded UI Test" - which I think replaces it as a whole. The Coded UI Testing minimizes coding and recorded your actions - while also allowing coding and customization.

So how it works is basically like this:

  1. It records your behaviors (on a browser/WPF/Silverlight etc application) 
  2. Then it tries to guess what you are doing (moving a mouse, hover, waiting, clicking a button, typing text, etc).
  3. Generate code to replicate your behaviors/actions based on its guess. 
  4. You can also create assertions, to check whether certain elements (like texbox) has certain value, some labels display certain text, etc.

I have to say that for my web application that I am working on, it does an excellent job. It does all the low end work of recording my actions - and all I have to do is string them all together into a coherent sequence of actions in my tests.

MSDN has an excellent walk through on how to start one and customizing it to fit your needs and I am not going to repeat it in my post. You can read the MSDN how-to here.

In my experience in using it, it has its quirks:
  1. In some AJAX scenarios it will retain the old value or view of certain actions. So let's say you are looking at a product administration "Detail" screen and you click "Edit" to bring up the editing capability. Upon save, your application then brings you back to the "Detail" screen. In this scenario, sometimes upon "Save", the Coded UI test still holds the old "view" of the "Detail" screen instead of reloading/refreshing with the new "Detail" screen with the new/updated values. As a result, when you have an assertion to check whether certain values are updated, it will fail.
  2. Updating and deleting an assertion test or a recording is quite difficult. You have to manually delete it in code all the way. Updating certain test is also quite difficult if you want to do it manually. So for example if I have a test that checks whether a particular textbox value is "Something" and I want to change it to check for "some things" instead, intuitively I went to look for the line of generated code and change the checking value. But upon running, the code is regenerated and my changes are reverted back to "Something".
  3. The generated code also combine most of the generated code into 1 UI map. Which gets huge once you start building multiple tests. MSDN has a walkthrough on how to build tests using multiple UI mappings, but it is quite a challenge.
Beyond those issues that I have experienced so far, the tool itself is pretty impressive and I like it.

Some more readings and how-tos from MDSN

-- read more and comment ...

Saturday, June 5, 2010

How to Suppress .NET Warnings

In my current project, there are several warnings (C#) that are caused by several lines of code resulting from CSLA inheritance. Those warnings are basically about a local variable that is assigned but never used. Completely harmless and localized.Or on a different scenarios, you may run a Code Analysis and it returns a bunch or warnings.

For the longest time, I just ignore those warnings. But when I moved from VS 2008 to VS 2010 and to .NET 4, I thought that now is the right time to suppress those warnings.

There are several ways to remove/suppress warnings:
  1. Obviously, the warnings are there for a reason, and maybe that reason is valid. Maybe you declare a variable that is never used and should be removed, or make some methods "static", or unreachable code, etc etc. If these warnings are valid - then you should fix your code.
  2. Please do not go do this step if you have not done #1 thoroughly. OK, now you decided that the code is correct but the warning is still there and you want to suppress it. In most cases, you can right click on the warning in the list and select "Suppress Message" and pick whether you want to suppress it inline in the code or put them in a separate GlobalSuppression.cs file. Only the warnings that have a "CA" number or "CheckId" can be suppress this way. Warnings that do not have CheckId must be handled in a different manner - see #3.
  3. Using #pragma. Read this for MSDN explanation of pragma. Basically, with pragma, you do this: #pragma warning [disable|restore] [CheckId]. The CheckId must not contain the "CA" prefix. 
There you go ... now we can sleep a bit better knowing we have less warnings in our code. 
-- read more and comment ...