Supporting multiple submit buttons on an ASP.NET MVC view

A while ago, I was asked for advice on how to support multiple submit buttons in an ASP.NET MVC application, preferably without using any JavaScript. The idea was that a form could contain more than one submit button issuing a form post to a different controller action.

The above situation can be solved in many ways, one a bit cleaner than the other. For example, one could post the form back to one action method and determine which method should be called from that action method. Good solution, however: not standardized within a project and just not that maintainable… A better solution in this case was to create an ActionNameSelectorAttribute.

Whenever you decorate an action method in a controller with the ActionNameSelectorAttribute (or a subclass), ASP.NET MVC will use this attribute to determine which action method to call. For example, one of the ASP.NET MVC ActionNameSelectorAttribute subclasses is the ActionNameAttribute. Guess what the action name for the following code snippet will be for ASP.NET MVC:

public class HomeController : Controller
{
    [ActionName("Index")]
    public ActionResult Abcdefghij()
    {
        return View();
    }
}

That’s correct: this action method will be called Index instead of Abcdefghij. What happens at runtime is that ASP.NET MVC checks the ActionNameAttribute and asks if it applies for a specific request. Now let’s see if we can use this behavior for our multiple submit button scenario.

The view

Since our view should not be aware of the server-side plumbing, we can simply create a view that looks like this.

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<MvcMultiButton.Models.Person>" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Create person</title>
    <script src="<%=Url.Content("~/Scripts/MicrosoftAjax.js")%>" type="text/javascript"></script>
    <script src="<%=Url.Content("~/Scripts/MicrosoftMvcAjax.js")%>" type="text/javascript"></script>
</head>
<body>

    <% Html.EnableClientValidation(); %>
    <% using (Html.BeginForm()) {%>

        <fieldset>
            <legend>Create person</legend>
            <p>
                <%= Html.LabelFor(model => model.Name) %>
                <%= Html.TextBoxFor(model => model.Name) %>
                <%= Html.ValidationMessageFor(model => model.Name) %>
            </p>
            <p>
                <%= Html.LabelFor(model => model.Email) %>
                <%= Html.TextBoxFor(model => model.Email) %>
                <%= Html.ValidationMessageFor(model => model.Email) %>
            </p>
            <p>
                <input type="submit" value="Cancel" name="action" />
                <input type="submit" value="Create" name="action" />
            </p>
        </fieldset>

    <% } %>

    <div>
        <%=Html.ActionLink("Back to List", "Index") %>
    </div>

</body>
</html>

Note the two submit buttons (namely “Cancel” and “Create”), both named “action” but with a different value attribute.

The controller

Our controller should also not contain too much logic for determining the correct action method to be called. Here’s what I propose:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new Person());
    }

    [HttpPost]
    [MultiButton(MatchFormKey="action", MatchFormValue="Cancel")]
    public ActionResult Cancel()
    {
        return Content("Cancel clicked");
    }

    [HttpPost]
    [MultiButton(MatchFormKey = "action", MatchFormValue = "Create")]
    public ActionResult Create(Person person)
    {
        return Content("Create clicked");
    }
}

Some things to note:

  • There’s the Index action method which just renders the view described previously.
  • There’s a Cancel action method which will trigger when clicking the Cancel button.
  • There’s a Create action method which will trigger when clicking the Create button.

Now how do these last two work… You may also have noticed the MultiButtonAttribute being applied. We’ll see the implementation in a minute. In short, this is a subclass for the ActionNameSelectorAttribute, triggering on the parameters MatchFormKey and MatchFormValues. Now let’s see how the MultiButtonAttribute class is built…

The MultiButtonAttribute class

Now do be surprised of the amount of code that is coming…

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultiButtonAttribute : ActionNameSelectorAttribute
{
    public string MatchFormKey { get; set; }
    public string MatchFormValue { get; set; }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        return controllerContext.HttpContext.Request[MatchFormKey] != null &&
            controllerContext.HttpContext.Request[MatchFormKey] == MatchFormValue;
    }
}

When applying the MultiButtonAttribute to an action method, ASP.NET MVC will come and call the IsValidName method. Next, we just check if the MatchFormKey value is one of the request keys, and the MatchFormValue matches the value in the request. Simple, straightforward and re-usable.

Đặng Thế Phong: Một tài năng đoản mệnh

Văn đàn Việt Nam những năm 1930-1945 đã phải chứng kiến nhà văn Vũ Trọng Phụng ra đi ở tuổi 27 (1939) vì bệnh lao để lại sự tiếc thương vô hạn cho những người yêu thích văn học nước nhà.

Năm 1940, chúng ta mất nhà thơ nổi tiếng Hàn Mặc Tử khi ông mới 28 tuổi vì bệnh phong.

Trong lĩnh vực âm nhạc, một tài năng khác cũng ra đi ở độ tuổi rất trẻ (24) cũng bởi căn bệnh thuộc hàng tứ chứng nan y như Vũ Trọng Phụng. Đó là Đặng Thế Phong.

Cũng như Vũ Trọng Phụng, phải mãi sau này khi làn gió đổi mới đến với đất nước ta thì các nhạc phẩm nổi đình đám một thời của Đặng Thế Phong và các nhạc sĩ tiền chiến khác mới được đánh giá một cách đúng mức trong kho tàng lịch sử âm nhạc Việt Nam mặc dầu từ rất lâu rồi nó đã có chỗ đứng vững chắc trong lòng người hâm mộ.

Cũng giống như Nguyễn Đình Thi, chỉ với hai bài hát cách mạng "Diệt phát xít" và "Người Hà Nội", ông đã là một nhạc sĩ nổi tiếng bậc cao thủ trong giới nhạc sĩ Việt Nam đương đại.

Đặng Thế Phong cũng vậy. Chỉ với ba bài hát "Đêm thu", "Con thuyền không bến" và "Giọt mưa thu", ông đã là nhạc sĩ có một không hai gắn liền tên tuổi bất hủ của mình với mùa thu. Xem thế đủ biết không phải cứ đẻ sòn sòn đã là hay. Vấn đề là ở chỗ ít mà tinh, mà để đời.

Đặng Thế Phong là vậy đó.

Sinh ra trong một gia đình công chức ở thành Nam nhưng không may mắn. Cha mất sớm buộc Đặng Thế Phong phải sớm tìm con đường mưu sinh: vừa đi học, vừa vẽ thuê kiếm sống.

Mới hơn hai mươi tuổi đầu đã lang thang nơi đất khách quê người tận xứ Nam Vang làm đủ thứ nghề vẽ thuê, dạy nhạc để sống, để học và để sáng tác. Năng khiếu bẩm sinh về âm nhạc cho phép Đặng Thế Phong có thể vừa ôm đàn, vừa sáng tác, vừa biểu diễn tác phẩm của mình với chất giọng tenor rất đặc biệt.

Theo các bạn bè và bà Đặng Thanh Kim, em út của Đặng Thế Phong thì ông là một thanh niên rất điển trai, hoạt bát, thích ăn diện, ăn nói rất có duyên lại giỏi đàn hát nên được rất nhiều cô gái thành Nam yêu mến. Đặc biệt Đặng Thế Phong có biệt tài sắm các vai nữ, y như thật. Nhiều cô gái mê ông vì thế.

Trong số đó có ba cô lọt vào mắt xanh chàng trai trẻ đa tình. Đó là cô Hà Tiên, học sinh Trường Sarcree coeur Nam Định; cô Nguyễn Thị Na, tức Lê ở khu Ga Hải Phòng; và cô Bạch Yến ở Hàng Bông, Hà Nội.

Trong ba cô thì Bạch Yến xem ra nặng tình hơn cả bởi cô là người chăm sóc và tiễn đưa Đặng Thế Phong đến nơi an nghỉ cuối cùng và buồn thay cuộc đời của cả ba người đều lỡ dở.

Đặng Thế Phong viết "Đêm thu" năm 1940. Ca khúc này ông viết và biểu diễn ở những đêm lửa trại, lời ca được nhiều bạn bè đóng góp chỉnh sửa nên rất trong trẻo hồn nhiên, thể hiện nỗi đam mê của con người trước thiên nhiên và cuộc sống. Ngay lập tức bài hát được giới trẻ hưởng ứng nhiệt liệt. Song phải đến "Con thuyền không bến" viết vào tháng 9/1941 sau khi nhạc sĩ đi Phnom Penh trở về thì tên tuổi Đặng Thế Phong mới nổi như cồn.

Hôm đó tại Nhà hát Lớn Hà Nội, ca sĩ Vũ Thị Hiển lần đầu tiên hát ca khúc này đã làm xôn xao dư luận. Sau đó chính tác giả đã trình bày bài hát này tại rạp Olimpia ở phố Hàng Da thì công chúng Hà Nội càng thêm mến mộ một tài năng. Không chỉ bởi chất giọng của người nhạc sĩ kiêm ca sĩ mà bởi chất thơ nhuần nhuyễn trong từng giai điệu và lời ca thẫm đẫm chất thu:

Đêm nay thu sang cùng heo may
Đêm nay sương lam mờ chân mây
Thuyền ai lờ lững trôi xuôi dòng
Như nhớ thương ai chùng tơ lòng.

Có một điều rất khó lý giải là tại sao ở cái tuổi mới hơn hai mươi mà Đặng Thế Phong lại nhuần nhuyễn từ ca từ đến làn điệu thấm đẫm chất dân ca đồng bằng Bắc Bộ như vậy.

Lướt theo chiều gió. Một con thuyền theo trăng trong.

Giai điệu này lặp đi lặp lại nhiều lần như một điểm nhấn, nó nghe như một làn điệu dân ca mơ hồ, chầu văn hay chèo nào đó.

Cũng lạ, trong lúc âm nhạc Pháp đang tràn ngập Việt Nam, tâm lý hướng ngoại đang là "mốt" trong giới trí thức, những đĩa hát tango chinoise 78 vòng/phút đầy chất lính kèn lê dương, phong trào tân nhạc chủ yếu là đặt lời cho các bài hát tây thì nhạc phẩm của Đặng Thế Phong lại thấm đẫm tâm hồn Việt…

Năm 1942, Đặng Thế Phong viết "Vạn cổ sầu", sau Bùi Công Kỳ sửa lời và đặt tên mới là "Giọt mưa thu". Đây là giai phẩm thứ ba của Đặng Thế Phong và lại có chủ đề là mùa thu:

 http://www.nhaccuatui.com/m/AqNq6Rpttr

Ngoài hiên giọt mưa thu thánh thót rơi
Trời lắng u buồn mây hắt hiu ngừng trôi.

Giọt mưa thu rơi thánh thót. Thật không có hình ảnh nào sống động chính xác hơn. Hơn nửa thế kỷ đã trôi qua, người ta vẫn ví những khúc ca lộng lẫy đó như là "hoa hậu" của ca từ âm nhạc hiện đại Việt Nam.

"Giọt mưa thu" là một nhạc phẩm song cũng là một mảng tâm hồn của con người. Nó như một lời ru kỳ diệu đưa hồn người hòa đồng vào các cung bậc cảm xúc đầy sắc màu của thiên nhiên, nó như giãi bày hộ nỗi buồn nhân thế đang mong được giải tỏa.

 

Một tiếng tơ lòng cất lên mỏng manh như tâm hồn người nghệ sĩ.

Đã bao năm rồi, đã có biết bao thế hệ người Việt Nam cất tiếng hát:

Ai nức nở thương đời
Châu buông mau, dương thế bao la sầu.

Sự tích Ngưu Lang – Chức Nữ chia xa, mỗi năm được gặp nhau một lần ngắn ngủi, nước mắt của tình yêu và nỗi nhớ giội từ trên trời cao xuống hiu hắt lắng đọng từ cõi vô biên, phải chăng đó là chất xúc tác để chàng nghệ sĩ họ Đặng cảm xúc cất lên những âm thanh siêu ảo vượt lên nỗi buồn thế tục, phải chăng giọt mưa thu chính là thiên sứ của tình yêu đã được nhân cách hóa một cách tài tình.

Hãy thử tưởng tượng trong một ngày mưa thu rơi thánh thót ngoài hiên, tiếng vĩ cầm cất lên réo rắt những giai điệu như nức nở của giọt mưa thu của Đặng Thế Phong, người ta có cảm nhận như đâu đây tiếng lòng thổn thúc của thơ Verlain, hay tiếng nhạc buồn của Chopin, hay những cánh lá vàng trong bức tranh "Mùa thu vàng" của Levitan. Thiên nhiên và lòng người hòa quyện một cách tài tình trong bàn tay sáng tạo của người nghệ sĩ.

Chỉ với ba nhạc phẩm thôi, Đặng Thế Phong đã là một hiện tượng trong lịch sử nền âm nhạc ViệtNam. Từ "Đêm thu" với những kỷ niệm tươi trẻ hồi thơ bé cùng Tết Trung thu:

Qua lá cành ánh trăng lan dịu dàng
Ru hồn bao nhớ nhung.

đến "Con thuyền không bến" mộng mơ:

Ánh trăng mờ chiếu.
Một con thuyền trong đêm thâu
Trên sông bao la thuyền mơ bến nơi đâu?

đã là một bước chuyển rất lớn trong tâm hồn người nghệ sĩ.

Đến "Giọt mưa thu": Nghe gió thoảng mơ hồ trong mưa thu ai khóc ai than hờ.

Có thể thấy Đặng Thế Phong đã hóa thân vào tiếng thu lòng thổn thức một cách tài tình như thế nào.

Trong số những người bạn học thân của Đặng Thế Phong hồi thiếu thời ở Nam Định có Vũ Đức Oong. Ông này sau tham gia cách mạng bị Pháp bắt giam ở nhà ngục Sơn La. Từ trong tù, nghe tin bạn bị lao mà chết, năm 1943, ông cảm thán viết bài thơ "Nhớ Thế Phong", trong đó có đoạn:

Đã mấy thu rồi xa cách lắm
Mấy lần thu tới mấy thu đi
Bạn ơi! Có biết thu này khác
Trăng úa bên rừng khóc biệt ly!

Cũng lại ý tứ mùa thu. Phải chăng hai người bạn nối khố này rất đồng cảm với nhau. Năm 1945 ra tù tham gia cướp chính quyền ở Nam Định, ông Oong đã đến ngay gia đình Đặng Thế Phong và còn giữ nhiều tấm ảnh quý về gia đình họ Đặng này. Ông nói: "Nếu tôi không bị đi tù thì tôi không để cho Phong đi Campuchia và ốm đau bệnh tật như thế!".

Thoắt đấy mà đã chín chục năm ngày sinh của một nhạc sĩ tài hoa nhưng đoản mệnh. Hôm qua chúng ta đã hát những ca khúc buồn của ông, hôm nay chúng ta tiếp tục hát những ca khúc của ông nhưng với một tâm thế khác. Ngày mai cũng vậy. Bởi lẽ đó là những ca khúc bất hủ của một tài năng đích thực

Password Recovery in an ASP.NET MVC Project

Password Recovery in an ASP.NET MVC Project

While rewriting my personal web site with ASP.NET I noticed that although support for the ASP.NET Membership Provider comes included out of the box in a ASP.NET MVC project not all the options are fully implemented to the same extend that they are in a brand new ASP.NET WebForms project. For example, the option to reset your own password if you forgot your old one is not available out of the box in an ASP.NET MVC project.

Out of the box the following options are fully implemented in a ASP.NET MVC project:

  • Login in
  • Login out
  • Change your password
  • Create new user

Adding support for Password Recovery to an ASP.NET MVC project turned out to be pretty easy as the core functionality already exists in the Membership Provider and it’s just a matter of calling it from your application.

The process that I implemented goes like this:

  • From the LogOn view users can go to the PasswordReset view
  • In the PasswordReset the user indicates his/her username and then they are sent to the QuestionAndAnswer view
  • In the QuestionAndAnswer view the user enters the answer to their own security question
  • Finally, the user is sent to the PasswordResetFinal view with a message indicating that their password has been reset and e-mailed to them.

New Views and Controllers

LogOn

The first thing that I did was update the LogOn view that comes with ASP.NET and added a link to start the Password Reset process. I wired this link to the a new method called PasswordReset in the AccountController.

password_logon

Password Reset

Secondly I created the HTTP-GET PasswordReset method in the AccountController and a very simple view (PasswordReset.aspx) to allow the user to enter his/her username so that we can reset their password. The PasswordReset.aspx view is extremely simple as it only has a textbox where the user enter their user name.

password_reset

   1: public ActionResult PasswordReset()
   2: {
   3:     if (!MembershipService.PasswordResetEnabled) throw new Exception("Password reset is not allowed");
   4:     return View();
   5: } 

I also implemented an HTTP-POST PasswordReset method in the AccountController to pick up the data and continue the process. This controller method decides whether the next step is to reset the password for this user or if we need to ask him/her a Password Recovery question before we reset their password. This step is required to honor the requiresQuestionAndAnswer configuration setting in the ASP.NET Membership Provider.

   1: [HttpPost]
   2: public ActionResult PasswordReset(string userName)
   3: {
   4:     if (!MembershipService.PasswordResetEnabled) throw new Exception("Password reset is not allowed");
   5:  
   6:     if (MembershipService.RequiresQuestionAndAnswer)
   7:     {
   8:         return RedirectToAction("QuestionAndAnswer", new { userName = userName } );
   9:     }
  10:     else
  11:     {
  12:         MembershipService.ResetPassword(userName, GetLoginUrl());
  13:         return RedirectToAction("PasswordResetFinal", new { userName = userName });
  14:     }
  15: } 
Password Question and Answer

If the Membership Provider is configured to require a question and answer before resetting a user’s password then we route users to the QuestionAndAnswer view. This view is also very simple as it merely has two labels (one with the username and another with password question for the user) and a textbox where the user will enter the answer to their password question.

Security Question View

To support this QuestionAndAnswerView I implemented an HTTP-GET controller method that fetches the security question for the username entered in the PasswordReset view.

public ActionResult QuestionAndAnswer(string userName)
{
    if (!MembershipService.PasswordResetEnabled) throw new Exception("Password reset is not allowed");
    ViewData["UserName"] = userName;
    ViewData["Question"] = MembershipService.GetUserQuestion(userName);
    return View();
}

Finally I added an HTTP-POST method to support the QuestionAndAnswer. By the time we get to this HTTP-POST method we have all the information that we need to reset a user’s password (namely the user name and the answer to the security question.) Hence this method is where the call to actually reset the user’s password actually happens.

[HttpPost]
public ActionResult QuestionAndAnswer(string userName, string answer)
{
    if (!MembershipService.PasswordResetEnabled) throw new Exception("Password reset is not allowed");
MembershipService.ResetPassword(userName, answer, GetLoginUrl());
    return RedirectToAction("PasswordResetFinal", new { userName = userName });
}

Password Reset Final

The last step in the process if a new view called PasswordResetFinal that just displays a message to the user telling him/her that a new password has been generated and e-mailed to them.

Password Reset Final View

Changes to the Model

Every ASP.NET MVC project comes with a default model called AccountMembershipService to support the Views and Controllers that handle membership information. This AccountMembershipService is not much more than a wrapper for the ASP.NET MembershipProvider. Adding functionality to this model to support the password reset operation was very simple as the MembershipProvider already provides the core functions. The MembershipService referenced in the controller actions in the code actually point to an instance of this AccountMembershipService.

For example, the QuestionAndAnswer view calls the following method to to retrieve the security question for a user. Notice how this method’s only job is to forward the calls to the Membership provider.

public string GetUserQuestion(string userName)
{
MembershipUser user = _provider.GetUser(userName, false);
    if (user == null)
    {
        throw new Exception("User name not found");
    }
    else
    {
    return user.PasswordQuestion;
    }
}

All in all I added two methods to the AccountMembershipService (one to retrieve a user’s security question and one to actually do the password reset) plus a few properties to expose a couple of features of the Membership provider (like the need for a security question) that were not exposed on the default implementation.

In Summary…

As I indicated at the beginning of this blog post, adding support for Password Recovery to an ASP.NET MVC project turned out to be pretty easy as the core of the functionality already exists in the Membership Provider.

JetBrains Intellij Idea 8.1.0

Phần mềm soạn thảo JAVASCRIPT tuyệt vời cho dân lập trình!
IntelliJ IDEA features excellent JavaScript editor for productive JavaScript programming. All of its features including code completion, error highlighting and refactoring, quick fixes and intention actions are JavaScript aware and let you productively create efficient JavaScript code.
IntelliJ IDEA is an intelligent Java IDE intensely focused on developer productivity. It provides a robust  combination of enhanced development tools, including refactoring, J2EE support, Ant, JUnit, and version controls integration. Packaged with an intelligent Java editor, coding assistance and advanced code automation tools, IntelliJ IDEA enables Java programmers to boost their productivity while reducing routine time consuming tasks.

JS_DOM_Completion

Key Benefits
— Increase developer’s capabilities
— Full-spectrum web-development support (HTML, CSS, JavaScript)
— Full JSP 2.0 specification support
— J2ME support
Prevent and fix bugs
— New Code Inspections
— New Intention Actions and Quick Fixes
— New Debugger Features
Work productively with code
— Quick Definition Lookup
— Code Inspection Profiles
— Enhanced code assistance and formatting
— Improved editor splitting and tab grouping
Understand and improve code design
— Module dependency viewer and backward/cyclic dependencies analysis
— New and enhanced refactorings
Save developers time navigating projects
— Favorites view
— External stacktrace-to-code navigation
— Welcome screen
Make it easy to work with teams
— New VCS Integrations (Subversion, Perforce)
— JBuilder/Eclipse project import
Enable developers to write plug-ins
— Expanded, improved API architecture
— New Language API
— New module type for plug-ins
File Size: 117 MB
http://rapidshare.com/files/197739437/inteledg.rar