Gosh, I feel like an idiot. For the whole day I was trying to get my Ext.NET + ASP.NET MVC project to handle cookie, finally I manage to get it done. Then I found out a very simple method which only need a few lines of JavaScript.
The Beginning
I have this login form created with Ext.NET.
The behavior that I want is that whenever the checkbox is checked, a cookie will be set to remember the username.
The first thing that came to my mind was, “Oh right, let the MVC controller handles it, I remember HttpRequest/HttpResponse has access to cookie”. So I came out with the following code:
ControllersAccountController.cs
public ActionResult Login() { var c = Request.Cookies["chkRememberMe"]; this.ViewData["chkRememberMe"] = c != null ? "true" : "false"; c = Request.Cookies["txtUsername"]; this.ViewData["txtUsername"] = c != null ? c.Value : ""; return View(); } [HttpPost] public ActionResult Login(string txtUsername, string txtPassword, string ReturnUrl, string chkRememberMe) { if (!String.IsNullOrEmpty(chkRememberMe)) { Response.Cookies.Add(new HttpCookie("chkRememberMe", "true")); Response.Cookies.Add(new HttpCookie("txtUsername", txtUsername)); } else { Response.Cookies["chkRememberMe"].Value="false"; Response.Cookies["txtUsername"].Value = ""; } // --- snip -- }
On the View portion, I amended it as follows:
ViewsAccountLogin.aspx
<ext:FormPanel runat="server" FormID="form1" Url='<%# Html.AttributeEncode(Url.Action("Login")) %>' Border="false" Layout="form" BodyBorder="false" BodyStyle="background:transparent;"> <Items> <ext:Container ID="Container1" Layout="column" runat="server" Height="25" AnchorHorizontal="100%"> <Items> <ext:TextField ID="txtUsername" runat="server" FieldLabel="Username" AllowBlank="false" Text='<%# this.ViewData["txtUsername"] %>' BlankText="Username is required." Width="225" /> <ext:BoxComponent Width="10" runat="server" /> <ext:Checkbox ID="chkRememberMe" Checked='<%# this.ViewData["chkRememberMe"] %>' runat="server" /> <ext:Label runat="server" FieldLabel="Remember Me" LabelSeparator=" " /> </Items> </ext:Container> <ext:TextField ID="txtPassword" runat="server" InputType="Password" FieldLabel="Password" AllowBlank="false" BlankText="Password is required." AnchorHorizontal="100%" /> </Items> </ext:FormPanel>
If you think this will work, you’ll be disappointed. Just like I did. Even after checking that both cookies are set, and properly fed to Login’s ViewData, the Login’s View page doesn’t seem to bother to read its ViewData.
So I came out with another strategy. I will save the ViewData to a hidden input, and use Ext.NET’s DocumentReady event to populate it.
<input type="hidden" id="vwchkRememberMe" value="<%=this.ViewData["chkRememberMe"] %>" /> <input type="hidden" id="vwtxtUsername" value='<%=this.ViewData["txtUsername"] %>' /> <ext:ResourceManager runat="server"> <Listeners> <DocumentReady Handler=" #{chkRememberMe}.setValue(Ext.get('vwchkRememberMe').getValue()); #{txtUsername}.setValue(Ext.get('vwtxtUsername').getValue()); " /> </Listeners> </ext:ResourceManager>
It works and I was a happy man.
How it ended
I was reading the Ext.JS documentation when I saw this:
Oh Gawd… I can easily set/read cookies using Ext.JS built in methods!!!
The final changes
<!-- snip ---> <ext:ResourceManager runat="server"> <Listeners> <DocumentReady Handler=" #{chkRememberMe}.setValue(Ext.util.Cookies.get('vwchkRememberMe')); #{txtUsername}.setValue(Ext.util.Cookies.get('vwtxtUsername')); " /> </Listeners> </ext:ResourceManager> <!-- snip ---> <ext:Button runat="server" Text="Login" Icon="Accept"> <DirectEvents> <Click Url="/Account/Login" Timeout="60000" FormID="form1" CleanRequest="true" Method="POST" Before=" Ext.Msg.wait('Verifying...', 'Authentication'); Ext.util.Cookies.set('vwchkRememberMe', #{chkRememberMe}.getValue()); Ext.util.Cookies.set('vwtxtUsername', #{txtUsername}.getValue()); " Failure="Ext.Msg.show({ title: 'Login Error', msg: result.errorMessage, buttons: Ext.Msg.OK, icon: Ext.MessageBox.ERROR });"> <EventMask MinDelay="250" /> <ExtraParams> <ext:Parameter Name="ReturnUrl" Value="Ext.urlDecode(String(document.location).split('?')[1]).r || '/'" Mode="Raw" /> </ExtraParams> </Click> </DirectEvents> </ext:Button> <!-- snip --->