[image]
Home MVC Storefront

My MVC Starter Template

I've been toying around with reorganizing the default MVC template and thought I would share it with people. I like the way it's come together.

Reorganized
When I was working heavily with Rails I came to really enjoy the way the applications are structured. It seemed... clean in the way all parts of the application had an especially relevant bucket to live in. I especially liked the way the application bits (logic, data access, controllers and views...) were kept nicely in the "app" folder.

I'll be honest and say I'd like to see our default MVC template change a little bit. Phil's team and I (I'm not on Phil's team - I just annoy them) discuss this stuff a lot - and it's been brought up a few times that perhaps I should make a template of my own to show what I'm thinking. And I think that's a great idea...

So I reorganized it some. Here's what I'd love to have my site look like:

subsonicmvc

You'll notice that I'm keeping the "App" folder approach, and sticking the Controllers in there as well as the Views. In addition I have a place for DataAccess and Services (business logic) as well as Logs and a folder for the Dependencies.

I've also partitioned a folder called "Public" - this is where (I think, at least) the support files should go, as well as any static files (like HTML, etc). I've also added CSS and Scripts folders too.

Yes it looks a lot like a Rails site, but if it works - why change it?

Basic Hookups
But why stop at folder organization? I did a few other things as well:

Every site needs logging - so I've plugged NLog
I like the implementation of the AccountController - but I made it a bit more generic and have it working now with an IAuthenticationService which uses both ASP.NET Membership as well as OpenID. And yes I've included those implementations in the Services folder.
Every site needs to email things - so I've created an IMailerService which implements SmtpMailerService as well as my favorite TestMailerService (which stores sent mail in a List<> rather than try to send it off to an SMTP server).
I expanded the Site.master a little bit to include a ContentPlaceholder in the Head of the document (for script registry).
I added jQuery (even though I know this is coming!) as well as jQuery calendar.
I also setup StructureMap to be the default ControllerFactory. DI comes wired "out of the box" as you can see by the "Bootstrapper.cs" file that's in the root of the  App folder. I've also taken the liberty of configuring a few things already for you - such as the logger and mailer services.

A ViewEngine of My Very Own
The default ViewEngine that comes with ASP.NET MVC (the WebFormViewEngine) looks to the root of the application for the Views folder, and I needed to change that if I wanted to shove everything into the App folder -  so I had to create my own :). Thanks to Phil and team for making this rockin easy - all I had to do was to overwrite the location formats and I was good to go:

public class SubSonicViewEngine : WebFormViewEngine
{

    public SubSonicViewEngine()
    {
        MasterLocationFormats = new[] { 
                "~/App/Views/{1}/{0}.master", 
                "~/App/Views/Shared/{0}.master" 
            };
        ViewLocationFormats = new[] { 
                "~/App/Views/{1}/{0}.aspx", 
                "~/App/Views/{1}/{0}.ascx", 
                "~/App/Views/Shared/{0}.aspx", 
                "~/App/Views/Shared/{0}.ascx" 
            };
        PartialViewLocationFormats = ViewLocationFormats;
    }

}

To implement this ViewEngine I had to add one line of code to Application_Start in the Global.asax:

 ViewEngines.Engines.Add(new SubSonicViewEngine());

... And that's all there was to it!

Open ID Support
I've also added Open ID support to the Login page, and I've left a place there for you to put your own ID Selector. To implement, you simply need to head over to IDSelector.com and fill in 3 bits of information. They give you some code, you come back and put it in place et voila! You have OpenID:

openid

I've included the OpenIdAuthenticationService class that I've been using with the Storefront as well. This class handles the redirect to OpenID (and also the callback) - you simply need to implement the code for integrating the user and their URL.

To get this to work, I have a new Action in the AccountController which I call directly:

        public ActionResult OpenIDLogin()
        {
            bool isValid = false;
            string claimedUrl = Request["openid.claimed_id"];

            if (!String.IsNullOrEmpty(claimedUrl))
            {
                Uri openIDUri = new Uri(claimedUrl);
                var svc = new OpenIDAuthenticationService();
                isValid = svc.IsValidLogin(openIDUri);
                if (isValid)
                {
                    string returnUrl = Request.Form["ReturnUrl"];
                    FormsAuthentication.SetAuthCookie(claimedUrl, false);

                    if (!String.IsNullOrEmpty(returnUrl))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }            
                }
            }
            return View("Login");
        }

The line "Request["openid.claimed_id"] might look weird - and you might be wondering why I'm 1) using "Request" instead of Request.Form and 2) why I've named it something like that.

The answer is that this action gets called twice - once by the login form (via POST when the user clicks "login"), and once by the OpenID provider (via GET on the redirect).  The Open ID provider will return a querystring which has the "openid.claimed_id" key in it, and I want to be able to read that in - so I need to access the entire Request name/value collection.

The Service class uses DotNetOpenID to redirect off to the provider, as well as receive the callback:

        public bool IsValidLogin(Uri serviceUri)
        {
            bool result = false;
            var openid = new OpenIdRelyingParty();
            if (openid.Response == null)
            {
                // Stage 2: user submitting Identifier
                openid.CreateRequest(serviceUri.AbsoluteUri).RedirectToProvider();
            }
            else
            {
                result = openid.Response.Status == AuthenticationStatus.Authenticated;
                if(result)
                {
                    //synch the users
                }
            }
            return result;
        }

... and there you have it.

And Finally - What This Isn't
I have bigger and badder plans for SubSonic than just this (I'm working on that stuff now) so even though this has the SubSonic name to it - please don't think it's what I've been working  on for the last 9 months :). This is the result of me geeking out over the weekend and wondering if others would find this useful.

What I'd really like is your feedback with respect to the things I've done with the template - specifically:

Organization Setup Included Technology What I've Left Out

The main reason is that if you like what you see here I can raise the ideas to the team and say "look what comments I've received on my blog". Or, conversely, if this is too complicated I can stop bugging them :).

Download the Template Here (uses Preview 5). Stick the zip file into your C:\Users\[USERNAME]\Documents\Visual Studio 2008\Templates\ProjectTemplates folder and restart Visual Studio. The template will show up under "My Templates":

templatedialog

Looking forward to your thoughts!

blog comments powered by Disqus
Search Me
Subscribe

Ads via The Lounge

Index Of MVC Screencasts

You can watch all of the MVC Screencasts up at ASP.NET, and even leave comments if you like.

Tag Cloud
[image]
Popular Posts
 
My Tweets
Got interviewed on Hanselminutes about my DDD quest! http://tinyurl.com/64f8y5 @RickStrahl Yep, think that's them. @rickstrahl that's exactly the floor I have - really good stuff. Make sure to let acclimate! Hey what's your favorite logo? http://tinyurl.com/5p39uv (4 of 4) Finally - yes, I think you should care about DDD. It's something I've been doing all my career, formalized. Good stuff.
  About Me

[image]

Hi! My name is Rob Conery and I work at Microsoft. I am the Creator of SubSonic and was the Chief Architect of the Commerce Starter Kit (a free, Open Source eCommerce platform for .NET)

I live in Kauai, HI with my family, and when my clients aren't looking, I sometimes write things on my blog (giving away secrets of incalculable value).


You are viewing a mobilized version of this site...
View original page here

How do you rate mobile version of this page?

Mobilized by Mowser Mowser