Showing posts with label ASP.NET MVC. Show all posts
Showing posts with label ASP.NET MVC. Show all posts

Friday, August 24, 2012

Draupner: Full Stack ASP.NET MVC Scaffolding


A little while back I announced on twitter that Mjølner had open sourced it's ASP.NET MVC scaffolding tool, Draupner:



Since then Draupner has been updated to produce ASP.NET MVC 4 apps, and all the dependencies have been updated too. So now since like a good time an introductory post about Draupner.


Why Did we Build Draupner?
Scaffolding is not a new concept. It's been used for while in other web frameworks, and moreover Steven Sandersons ASP.NET MVC scaffolding has been around for a while too. That begs the question why another scaffolder? Basically because the existing ASP.NET MVC one does not do what we (Mjølner) want the way we want it: We want a simple command line tool that can

  • Set up a new ASP.NET MVC solution with a "Web" project along with an associated "Core" project and a "Test" project.
  • Add further entities to the solution as needed throughout the solutions lifetime
  • Add CRUD operations and GUIs to existing entities
  • Add tests for all the other stuff it adds
  • Allow us to code away happily on the solution without having to think about making the scaffolding tool happy

Furthermore, and importantly, we wanted everything the tool produced to follow an architecture we've used successfully time and again. This means setting up a certain structure in terms of projects and folders, as well as building on a certain technology stack that we like to work with. In other words the tool, Draupner, is a set of practices we at Mjølner have had succes with put into code. These last bits are what sets Draupner apart.

What Technology Stack does Draupner Set Up?
Draupner projects uses a bunch of technologies, that we've found to work well together. All of them are set up as NuGet dependencies (except Rake). The stack includes:


You can see the full list on the Draupner page on Github.

What Does a Draupner Solution Look Like?
Let's have a quick glance at a solution built with Draupner. This screenshot shows which projects such a solution consists of:



The .Web project is the ASP.NET MVC site: It includes views and some thin controllers, that rather quickly call into the .Core project.

The .Core project is where the domain model goes and where the persistence of said domain model is handled. We like intelligent domain models, so this is where the smarts of the application is meant to go.

The .Test project contains xUnit tests for both the .Web and the .Core projects.

This is all set up by Draupner during the initial project creation. Moving on from there Draupner can add further entities to the domain model and add CRUD operations/GUIs to those enitites. Taking a look inside the .Core project we see:



This gives a peek into the technolgoy stack used by Draupner projects: Entities are persisted to a SQL Server database via NHibernate (you can reconfigure NHibernate all you want if you e.g. want to change to MySql), and the NHibernate mappings are set up with Fluent.NHibernate. Draupner also create repositories for the enities it creates which the the controllers in the .Web project can use.

Also notice the Castle.Windsor dependency: All the code produced by Draupner uses dependency injection and inversion of control.Caslte.Windows is the IoC/DI container of choice used by Draupner proejcts. E.g. the repositories mentioned above expect an IUnitOfWork into which it can enroll operations. This is injected into them by Windsor. Skipping ahead a bit let me mention that the .Web project sets up an NHibernate unit of work per web request and registers it with Windsor.

Lastly we can notice that Draupner sets up Log4Net, so that it's ready to go.

Let's move up the stack and open up the .Web project:



We can see that Draupner has created controllers for the enities it created. These each allow for simple CRUD operations.

Draupner has also created simple, but nice Ajaxy CRUD views for the entities. Neither of these are really expected to be used in production, but act as placeholders until "the real thing" is implemented.

Draupner has also created a few view models, which are used in the CRUD GUIs and has set up Automapper configurations to map between the view models and the enitites in .Core.

Worth mentioning is also that the .Web project uses Elmah for error logging in the web layer.

As mentioned Draupner creates tests for all this as well. They end up the .Test project:

The tests are xUnit tests and use AutoFixture and Rhino.Mocks.

So What Now?
If this caught you're interest go clone the Draunper sample project on Github and take a harder look at how things are set up or take Draupner for a spin, following the instructions in the readme. If you like it, but find something missing or not working let us know. We're not making any promises with regards to support and bug fixes though, so an even better idea is to send a pull request. Those we do welcome.

Wednesday, May 4, 2011

Building DCI Context with ASP.NET MVC

In this post I'll address one of the questions that I tend to get when talking about DCI: How is the DCI context built at runtime?

To that end lets expand a bit on the DCI with ASP.NET MVC sample that I showed in an earlier post. The focus of that post was how to fit ASP.NET MVC and DCI together in a nice cohesive architecture. In this post I will zoom in on how the controller can build up the DCI context object in a conversation with the user.

The example I'm using is still that of a very simplified online bank, where the user can trasfer money between accounts. The core DCI parts of this example is explained in this post, and the connection with ASP.NET MVC in this post. Whereas the sample in the last post simply asked the user to input all the information about the transfer in one screen, this version asks for the information one thing at a time in a wizard like fashion. Whether this is good UX, is besides the point of this post. I just want to use an example where the context is build in a series of interactions with the user.

Interaction Between User and Code
First off the user is asked to choose a source account on this simple (ugly) page:



Serving up this page is done by this rather straight forward action method:

    1  public ActionResult SelectSource()
    2  {
    3      Session["Context"] = new TransferMoneyContext();
    4      return View(new SelectAccountVm
    5                  {
    6                      SelectedAccountId = string.Empty,
    7                      Accounts = accountRepo.Accounts
    8                  });
    9  }
   10 

Worth noticing though, is that a MoneyTransferContext object is created and stored in the session.
When the user hits the Next button this action is hit:

   55 [HttpPost]
   56 public ActionResult SelectSource(SelectAccountVm model)
   57 {
   58     var ctx = Session["Context"] as TransferMoneyContext;
   59     ctx.Source = 
   60       accountRepo.GetById(int.Parse(model.SelectedAccountId)) as TransferMoneySource;
   61     return View("SelectDestination", 
   62                 new SelectAccountVm
   63                 {
   64                     SelectedAccountId = string.Empty,
   65                     Accounts = accountRepo.Accounts
   66                 });
   67 }
   68 

This code updates the context with the chosen source account, and serves the next view in the interaction, where the user is asked for a destination account:



When the user hits this Next button this action is hit:

   69 [HttpPost]
   70 public ActionResult SelectDestination(SelectAccountVm model)
   71 {
   72     var ctx = Session["Context"] as TransferMoneyContext;
   73     ctx.Sink = 
   74       accountRepo.GetById(int.Parse(model.SelectedAccountId)) as TransferMoneySink;
   75     return View("SelectAmount", new SelectAmountVm());
   76 }
   77 

which does almost the same as the previous action, except it puts the chosen account in the Sink property on the context, and then shows this page:



The post from this page does a bit more work. First it updates the context with the amount given by the user. At this point the MoneyTransferContext is complete and ready to be exectued. Finally a result page is shown:

   78 [HttpPost]
   79 public ActionResult SelectAmount(SelectAmountVm model)
   80 {
   81     var ctx = Session["Context"] as TransferMoneyContext;
   82     ctx.Amount = model.SelectedAmount;
   83 
   84     ctx.Execute();
   85 
   86     return ResultPage(ctx);
   87 }
   88 

and the result page is:



Summing Up

To sum up: To build up a DCI context in ASP.NET MVC simply store a context object in the session context when a use case is started and execute it when it makes sense from a functionality perspective. This way the controller code is kept very simple, concentrating only on building up the context through interaction with the user, and the details of the use case execution is - from the perspective of the cotroller - hidden behind the context. Furthermore because of the way the controller builds the context the context object only knowns the domain objects through the roles they have been assigned by the controller - or in fact the user - allowing for the full strenght of DCI to play out there.

You can find the complete code from this post on GitHub.

Thursday, January 13, 2011

Doing DCI with ASP.NET MVC

The DCI - Data, Context, Interaction - paradigm (intro article, an earlier post) brings the roles domain objects play at runtime to center stage. DCI also fits right into the gaps of MVC. What? Which gaps?

MVC Gaps
Back in the day, when MVC was originally described by Trygve Reenskaug as an architecture approach it was all about the users mental model, giving the user the sense of just working directly with the domain objects. Now dont confuse this with the dreaded CRUDy forms-over-data battleship grey enterprise app. Those apps force the user to manipulate the data directly; respecting, fighting and being forced into submission by the techniocal details of databases. MVC on the other hands puts that the model is the users mental model - the programmer, then has to deal with hiding the technicalities of persistence and such. As illustrated below the users works as if manipulating the domain objects directly. The view simply reflects the model state, the controller reacts to user actions, and translates them to model updates, and that's it.
Direct manipulation metphor as illustrated by Trygve Reenskaug
This is fantastic for fairly simple apps. But as soon we introduce business rules with a certain amount of complexity, the direct manipulation metaphor does not suffice anymore. We need somewhere to put those business rules.  -The controller already has clear responsibility, so in keeping with single responsibility principle that's not the place for the behaviour. -The traditional OO answer is to put the behaviour into the model, but that leads to hard-to-follow logic jumping back and forth in the model objects, and (gark) up and down long inheritance chains. Moreover it turns out that a given domain object will play different roles over times. I.e. the object doesn't need just one behaviour, it needs several, and even worse it needs different behaviours over time. There goes SRP again, only this time in the "intelligent model".

Roles and  Contexts to Fill the Gap
So we need something more than MVC: The view is not the place for the behaviour, the model is not the place for the bahivour, and the controller is not the place for it either. This is where roles as separate things come into play. We want explicit roles. We want those business rules implemented in the roles. And we want to assing those roles to domain objects as needed.

The role a given object plays at a given moment depends on the context at that moment. So why not introduce contexts as something explict along with the explicit roles? Together roles implementing behaviour and contexts assigning roles to objects fill the gap in MVC.

Back to APS.NET MVC
Lets get practical: Where do the contexts and the roles go then? Since the contexts manage assigning roles and kicking off the behaviuour the contexts and roles fit well together. In the ASP.NET MVC + DCI demo I did for ANUG I organized the code like this:

 The Contexts folder has a subfolder for the use case I demoed. Other use cases would have their own subfolders. Inside the subfolder is the context for executing that use case, and the associated roles.

What is a role in C#? A role in C# is a set of extension methods on an interface (see this and that for more on roles in C#):

    1     public static class TransferMoneySourceTrait
    2     {
    3         public static void TransferTo(this TransferMoneySource self, TransferMoneySink recipient, decimal amount)
    4         {
    5             // The implementation of the use case
    6             if (self.Balance < amount)
    7             {
    8                 throw new ApplicationException(
    9                     "insufficient funds");
   10             }
   11 
   12             self.Withdraw(amount);
   13             self.Log("Withdrawing " + amount);
   14             recipient.Deposit(amount);
   15             recipient.Log("Depositing " + amount);
   16         }
   17     }

How does the context track the role assignments? Simple:

    8     public class TransferMoneyContext
    9     {
   10         public TransferMoneySource Source { get; private set; }
   11         public TransferMoneySink Sink { get; private set; }
   12         public decimal Amount { get; private set; }
   13 
   14         public TransferMoneyContext(TransferMoneySource source, TransferMoneySink sink, decimal amount)
   15         {
   16             Source = source;
   17             Sink = sink;
   18             Amount = amount;
   19         }
   20 
   21         public void Execute()
   22         {
   23             Source.TransferTo(Sink, Amount);
   24         }
   25     }
   26 

Where are the objects mapped to roles? Right in the seam between the controller and the context (lines 35 to 37):

   11     public class TransferMoneyController : Controller
   12     {
   13         AccountRepository accountRepo = new AccountRepository();
   14 
   15         public ActionResult Index()
   16         {
   17 
   18             ViewData["SourceAccounts"] =
   19                 accountRepo.Accounts.Select(a => new SelectListItem {Text = a.Name, Value = a.Id.ToString()});
   20             ViewData["DestinationAccounts"] =
   21                 accountRepo.Accounts.Select(a => new SelectListItem {Text = a.Name, Value = a.Id.ToString()});
   22             return View();
   23         }
   24 
   25         [AcceptVerbs(HttpVerbs.Post)]
   26         public ActionResult Index(FormCollection form)
   27         {
   28             var sourceAccountId = form["SourceAccounts"];
   29             var destinationAccountId = form["DestinationAccounts"];
   30             var amount = form["Amount"];
   31 
   32             var sourceAccount = accountRepo.GetById(int.Parse(sourceAccountId));
   33             var destinationAccount = accountRepo.GetById(int.Parse(destinationAccountId));
   34 
   35             new TransferMoneyContext(sourceAccount as TransferMoneySource,
   36                 destinationAccount as TransferMoneySink,
   37                 decimal.Parse(amount)).Execute();
   38 
   39             ViewData["Amount"] = amount;
   40             ViewData["Source"] = sourceAccount.Name;
   41             ViewData["Destination"] = destinationAccount.Name;
   42 
   43             return View("Result");
   44         }
   45     }

Apart from lines 35 to 37 this is all just standard ASP.NET MVC stuff: Getting data in and out of the ViewData, and returning the view to render back to the user.

Summing Up
MVC is great for simple situations. It doesn't quite scale to complex business scenarios, but DCI does, and the two are a great match.
Leveraging the power of C# to do DCI and the niceness of ASP.NET MVC to go along with it, makes for a - IMHO -very compelling architecte style for an enterprisy web app.

Monday, December 6, 2010

RHoK'ing for Unicef

I was at the RHoK 2.0 Aarhus event this weekend, and got the opportunity to do a simple little web app for Unicef. The app itself is not that interesting for people outside of Unicef, but it will save real money for Unicef that they can use on something else...like helping children. The app is something like 80% done, and we did it in about 28 hours. Wow, it feels great to have been able to actually help Unicef just by doing a saturday to sunday hackathon along with a few other geeks.

The app was done in ASP.NET MVC 2, with Enitity Framework 4 and SQL Express underneath, and the experience was pretty good: The architecture just came out of the box with MVC. EF code first made thinking about the database schema a non-issue (and the load on the app is expected to be low, so I don't think will need to go in a tweak for performance later). We were able to get by with some of the auto generated CRUD views that Visual Studio can make for ASP.NET MVC model objects. All in all the development was pretty quick.
The code is on google code.