December 2007 - Posts

In my quest to get my wpfstyle.com site written in the new ASP.Net MVC framework (day 3) I've run across a little issue that I'm sure will come up again.

In my world, a checkbox always seemed to imply true/false or yes/no.  In reality, it can mean a lot of things in an Html Form.  It's an input, remember, and inputs have a value.  When your checkbox is checked, that value is posted back. 

Making it work as a boolean indicator in your MVC application, is possible though.  In keeping with the Membership/Authorization theme from yesterday, I have the following controller action:

public void Authenticate(string userName, string password, bool? rememberMe)
[Hint: Notice the '?' after bool for the third parameter.  That'll be important in a moment.]
Here is the corresponding Login.aspx View which contains a form posting to this action:
<%using (Html.Form("Authenticate", "Account"))
  { %>
    <div style="margin: auto auto 4px auto">Username 
        <%=Html.TextBox( "username") %> </div>
    <div style="margin: auto auto 4px auto">Password &nbsp;
        <%=Html.Password( "password") %></div>
            
    <div style="margin: auto auto 4px auto">
        <%=Html.CheckBox("rememberme", "Remember Me", "true", false)%>
    </div>
    <div><%=Html.SubmitButton( "Log In") %></div>
<%} %>

Looking at our intellisense for Html.Checkbox, we seeimage 

By setting the checkbox's value to "true" we're going to have that value sent back through the MVC pipeline to our Action which has a boolean parameter rememberme.  It's not just any boolean though, it's a nullable boolean.  Remember when I meantion the distinction that the checkbox being checked causes the value to be posted back?  Well if the checkbox is *not* checked, the rememberme value will be null. 

The MVC pipeline is nice enough to implicitly convert the "true" string to a boolean, but null is not necessarily false in all cases.  To account for this, we must make our parameter a nullable boolean.  Does this maybe cross the line into mixing UI and Controller... eh - possibly?

(NOTE: If you don't see the Checkbox method in your intellisense, make sure you picked up and referenced the MVC Toolkit)

with no comments
Filed under:

So last weekend I picked up the new ASP.Net 3.5 Extensions Preview CTP (and MVC Toolkit) from the ASP.Net team and I'm loving the MVC bits.  I never could get in to MonoRail mainly because I'm a developer diva.  I need intellisense, syntax highlighting, the whole deal.  For a CTP, this release packs quite a punch.

After running through Scott Hanselman's MVC How-To Screencast and playing around I took to writing a full site I had already 90% completed with Community Server (wpfstyle.com - it's coming).  Blew threw most of the functionality in the first 3 or 4 hours - awesome.  Then I tried to add Forms Authentication through the easy ASP.Net Configuration button of VS 2008.  Nada.

Long story short, I figured out how to get things working, but there are some manual steps.  Here they are:

image[Step 1] Create a new ASP.Net MVC site.  I've called mine SecureMVCApplication.

[Step 2] Lets add a new controller called SecureController.  This will be our set of actions that only administrators can access. 

 

 

image [Step 3] We don't need to add any new Actions, the Index action created for us is sufficient, but we will need to do something.  So add a call to RenderView("Index") within the Index method.  You'll also need to create the index view, so add a folder called Secure under the Views folder already in your project.  To this we will need to add a new MVC View Page item.  To make it clear, I've typed "This is for admin eyes only!!!" as the body of my view.

At this point we should make sure things are working.  Hitting F5 should take you to the root of the site, but you could well end up at /Views/Secure/Index.aspx or something like that.  Try browsing to http://localhost:<port>/secure/index.  You should see the "This is for admin eyes only!!!" text.  If not, go watch Scott's screencast and come back.

image [Step 4] We're ready to start securing things.  Use the ASP.Net Configuration button to set security to Internet, create a couple of users and at least 1 role called Administrators.  This is for our example, you can call your roles whatever you want in your application.

At this point, you would normally use the Create Access Rules link to specify the Adminstrators role has access to the secure directory.  Instead, we have to do this bit ourselves, because the MVC pattern will present us with a URL structure that does not map to physical directories.  At least, probably won't.  In a normal site, the ASP.Net Configuration tool would add a web.config to each configured directory that specifies the authorization rules.  This brings us to the next step:

[Step 5] Open your projects root web.config and add the following:

<location path="secure">
  <system.web>
    <authorization>
      <allow roles="Adminstrators" />
      <deny users="*" />
    </authorization>
  </system.web>
</location>

Assuming you are familiar with MVC URLs this is telling us that the http://<site>/secure path should allow access to users in the Adminstrators role and deny everyone else.  /secure is, of course, the controller.  Had this been a standard site, the stuff inside the <location /> element would have been found inside our secure\web.config.

[Step 5] We are now ready to authenticate our users, but we don't have a normal login.aspx.  Instead, we're going to create a controller called UserController and add a Login and Authenticate action.  Here's what I've added to my sample:

namespace SecureMvcApplication.Controllers
{
    public class UserController : System.Web.Mvc.Controller
    {
        [System.Web.Mvc.ControllerAction]
        public void Login()
        {
            RenderView("Login");
        }

        [System.Web.Mvc.ControllerAction]
        public void Authenticate(string username, string password)
        {
            if (System.Web.Security.Membership.ValidateUser(username, password))
            {
                System.Web.Security.FormsAuthentication.RedirectFromLoginPage(username, false);
            }
        }
    }
}

Notice that my Login action is simply displaying a view.  This view has two textboxes (one marked password) and a submit button.  If you watch(ed) Scott's Screencast, I've used the http://asp.net/downloads/3.5-extensions/MVCToolkit.zip to do this.  The form itself looks like this:

<%using (Html.Form("Authenticate?ReturnUrl=" + this.Request["ReturnUrl"], "User"))
  {%>
    <div>Username: <%=Html.TextBox("username") %></div>
    <div>Password: <%=Html.Password("password") %></div>
    <div><%=Html.SubmitButton("Login") %></div>
<%} %>

Upon Submit/Login, we're POSTing to the Authenticate( string, string ) Action in our UserController which implements the basic Forms Authentication (above).  The next step is optional, but it helped me watch the authorization status.

[Step 6] (Optional)  Add this to your global.asax.cs to see the authorization status of your requests..

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];

    if (null == authCookie)
    {//There is no authentication cookie.
        Debug.WriteLine("Don't know you, dude.");
    }
    else
        Debug.WriteLine("Enjoy the party!");
}

Now F5 and browse to http://localhost:<port>/secure/index and you should be taken to the http://localhost:<port>/user/login page.  Upon hitting login, you're directed back to the root of the site.  In our form, we had to manually set the ReturnUrl, because Forms Authentication assumes you will be posting back to yourself (classic ASP.Net Web Form).  We're posting across to the Authenticate action Url.

You can download the completed VS 2008 project I used here.

Can you believe we're already calling ASP.Net Web Forms "classic"?  Now we need to get MVC into the WPF platform.  How cool would that be!

with 13 comment(s)
Filed under: ,

imageI posted recently a manual .reg file for adding the NHibernate Query Generator custom tool to Visual Studio 2008.  I just sent Ayende an update to the .Setup Product.wxs, a WiX file, which adds a new fixture specifically for 2008. 

If you are interested in building the installer and running the trunk of NHQG, below is my batch script.  Obviously, you'll have to change a couple of paths, but it should get you started. 

You can download the Product.wxs pending Ayende approving the new Product.wxs file here.

echo Off
set path=%path%;c:\tools\svn-win32-1.4.4\bin

echo get Trunk (Non-Recursive)...
svn co
https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk trunk -q -N
echo done

echo get Art...
svn co
https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/Art trunk/Art -q
echo done

echo get SharedLibs...
svn co
https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/SharedLibs trunk/SharedLibs -q
echo done

echo get NHQG...
svn co
https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/NHibernate.Query.Generator trunk/NHibernate.Query.Generator -q
echo done

echo build NHQG...
pushd .
cd trunk\NHibernate.Query.Generator
%windir%\Microsoft.NET\Framework64\v2.0.50727\msbuild.exe default.build
echo done

echo build Installer
cd NHibernate.Query.Generator.Setup
%windir%\Microsoft.NET\Framework\v2.0.50727\msbuild.exe Setup.wixproj
echo done
popd
PAUSE

with 1 comment(s)
Filed under: ,