After Thought

Posts Tagged ‘Fubu Mvc

Unit of Work Part 2

leave a comment »

In the previous post we started off with a brief discussion on Unit of Work and its implementation. We also implemented  ISessionContainer that is a wrapper for ISession and used it to persist changes into the database. In this post let us see if we can isolate the below piece of code that has to be repeated in all the methods that deals with repository.

try
{
	// do work
	_repository.Save(Entity);
	_sessionContainer.Commit();
}
finally
{
	_sessionContainer.Dispose();
}

Following implementation is inspired by Fubu Behaviors concept. Imagine every call from the client or web as a request and this request has to pass through a Request handler to reach our business logic. Let us create an interface IRequestHandler that would attempt to encapsulate a Request.

public interface IRequestHandler
{
  TOutput ProcessRequest<TInput1, TInput2, TOutput>(TInput1 input1, TInput2 input2, Func<TInput1, TInput2, TOutput> func)
    where TInput1 : class
    where TInput2 : class
    where TOutput : class;
}

The above interface takes in two input entities and a func that process these input entities and returns an output entity. Now let us go ahead and implement it.

public class AtomicRequestHandler : IRequestHandler
{
	private readonly ISessionContainer _sessionContainer;

	public AtomicRequestBehavior(ISessionContainer sessionContainer)
	{
		_sessionContainer = sessionContainer;
	}

	public TOutput ProcessRequest<TInput1, TInput2, TOutput>(TInput1 input1, TInput2 input2, Func<TInput1, TInput2, TOutput> func)
		where TInput1 : class
		where TInput2 : class
		where TOutput : class
	{
		try
		{
			var output = func.Invoke(input1, input2);

			_sessionContainer.Commit();

			return output;
		}
		finally
		{
			_sessionContainer.Dispose();
		}
	}
}

The name AtomicRequestHandler (name is subject to change upon a better name suggestion) means Handler for one request (imagine a web request). Initialized SessionContainer gets injected to AtomicRequestHandler.The ProcessRequest method invokes the method that has to be executed which in this case is UpdateBook. Upon completion of execution of UpdateBook method, it commits the transaction and closes the session. In case of any error anywhere in the execution, the transaction and session are closed throwing away all the unsaved changes.

Now let us re-implement the UpdateBook method with AtomicRequestHandler in mind.

public class SampleService : ISampleService
{
   private readonly IRepository _repository;

   public SampleService(IRepository repository)
   {
      _repository = repository;
   }

   public Book UpdateBook(Book book, Author author)
   {
      book.AddAuthor(author);
      book.Price =100m;
     _repository.Save(book);
     return book;
   }
}

The above illustration has no sign of SessionContainer at all. The reason we were able to separate the code so easily is because of Inversion of Control.

StructureMap is IoC of choice in my implementations, but you can choose to use your favorite IoC.  The following code shows how all this is magically constructed.

ISampleService sampleService = ObjectFactory.GetInstance<ISampleService>();
IRequestHandler atomicRequestHandler = ObjectFactory.GetInstance<IRequestHandler>();
Book result = atomicRequestHandler.ProcessRequest<Book, Author, Book>(GetBook(), GetAuthor(), sampleService.UpdateBook)

The above code calls atomicRequestHandler.ProcessRequest method with input entities – Book and Author and sampleService.UpdateBook method as a delegate that makes sure that the UpdateBook method is executed within the transaction boundary.

This is exactly how Fubu makes sure your web Request is executed within a transaction boundary. The Handle Request method in ActionHttpHandler redirects request to the action method through a behavior similar to AtomicRequestHandler.

You can implement this in ASP.net MVC by writing your own CustomHttpModule that initializes a new SessionContainer on BeginRequest and disposes it on EndRequest. You can alternatively do this in Application_BeginRequest and Application_EndRequest in Global.asax.cs file. ActionFilter is another place where you can stick in unit of work, but it is generally not recommended as you will have to do this for every single action.

If you compare them, Fubu does it the best when compared to ASP.Net Mvc, because of its architectural preference of Composition over Inheritance.

Finally, I wouldn’t have been able to write this exhaustive analysis on Unit of Work if not for multiple discussions with Chad Myers, Josh Flanagan and Weston Binford. Download the sample application on which the examples discussed above are based on.

Written by shashankshetty

October 29, 2009 at 10:33 pm

Unit of Work Part 1

with 4 comments

Quoting from Martin Fowler’s Patterns of Enterprise Application Architecture, “Unit of Work maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems”.

This post delves into the details and implementation of Unit of Work based on Martin Fowler’s explanation of Unit of Work in his book. First, we will try to understand the Unit of Work concept, then implement a Unit of Work and finally, we will see how it can be effectively used in a sample application.

An application request can be atomic (affecting single business object) or composite in nature (affecting multiple business objects). It becomes even more tricky when a database has to be updated with these changes. If you imagine a scenario where a request updates multiple business objects, then the following questions arise.

  • Do you make multiple calls to the database to save each of the objects  ?
  • You save all of them together into the database ?

The main drawback of the former approach is that your request handler has to be database aware. It has to make multiple calls to database for each and every request and if there is any error in the process, rollback the changes. Other issues are having to keep the transaction open throughout the request and maintain referential integrity when saving the objects into the database.

The latter approach keeps track of all the business objects that were changed during a request and at the end of the request all the business objects that were changed are saved into the database. This may involve opening a transaction, committing the changes and then closing the transaction. For this approach to work, it needs someone to track the objects that were changed, managing transaction and committing the changes. This is exactly what Unit of Work is intended to do.

Unit of Work keeps track of all the objects that are changed during a request, open a transaction, save the business objects in to the database and then close the transaction. In case of error, rollback all the changes. By doing this, it also accomplishes another important aspect of development – separation of concern which will be discussed in detail in part 2. Thus, the developer need not worry about persisting business objects into the database or dealing with database calls.

Before we go and implement our own Unit Of Work, let us see if there is already something out there that we can use. ISession in NHibernate represents the conversation between application and the database. ISession is just a container for Unit of Work that keeps track of objects that are changed during a request.

To leverage the Unit of Work in ISession, let us go ahead and implement ISessionContainer that wraps an ISession.

public interface ISessionContainer : IDisposable
{
	void Commit();
	ISession CurrentSession { get; }
}

public class SessionContainer : ISessionContainer
{
	private readonly ITransaction _transaction;
	private bool _isDisposed;

	public SessionContainer(ISessionFactory sessionFactory)
	{
		CurrentSession = sessionFactory.OpenSession();
		_transaction = CurrentSession.BeginTransaction();
	}

	public void Commit()
	{
		if (_isDisposed)
		{
			throw new InvalidOperationException(&quot;Could not commit as Unit of Work was not initialized&quot;);
		}
		_transaction.Commit();
	}

	public ISession CurrentSession { get; private set; }

	public void Dispose()
	{
		if (_isDisposed) return;
		_transaction.Dispose();
		CurrentSession.Dispose();
		_isDisposed = true;
	}
}

Creating a new instance of SessionContainer opens a new Session and starts a new transaction. It also has a Commit method that saves all the changes to the database and closes the transaction. Dispose method closes the transaction if not already closed and then closes the Session.

The next step is to delegate persistence management to SessionContainer. Let us imagine a situation where we want to update Book details that is still in works with the newly recruited high profile Author and update the projected price of the book. Before we proceed with the example here are the details of the Book and Author and their properties.

public class Book : DomainEntity<Book>
{
        public Book()
	{
		Authors = new List<Author>();
	}

	public virtual string ISBN { get; set; }
	public virtual string Title { get; set; }
	public virtual decimal Price { get; set; }

	public virtual IList<Author> Authors { get; private set; }
	public virtual void AddAuthor(Author author)
	{
		if (!Authors.Contains(author))
		{
			author.AddBook(this);
			Authors.Add(author);
		}
	}
}

public class Author : DomainEntity<Author>
{
	public Author()
	{
		Books = new List<Book>();
	}

	public virtual string Name { get; set; }

	public virtual IList<Book> Books { get; private set; }
	public virtual void AddBook(Book book) { ... }
}
public class Author : DomainEntity<Author>
{
public Author()
{
Books = new List<Book>();
Publishers = new List<Publisher>();
}
public virtual string Name { get; set; }
public virtual IList<Book> Books { get; private set; }
public virtual IList<Publisher> Publishers { get; private set; }
public virtual void AddBook(Book book)
{
if (Books.Contains(book))
return;
book.AddAuthor(this);
Books.Add(book);
}
public virtual void AddPublisher(Publisher publisher)
{
if (!Publishers.Contains(publisher))
{
publisher.AddAuthor(this);
Publishers.Add(publisher);
}
}
}

UpdateBook is a method (imagine an action method in a MVC Controller) that adds the new author to the Book and updates the price.

public class BookService : IService
{
    private readonly IUnitOfWork _sessionContainer;
    private readonly IRepository _repository;

    public BookService(IUnitOfWork unitOfWork, IRepository repository)
    {
        _sessionContainer = unitOfWork;
        _repository = repository;
    }

    public Book UpdateBook(Book book, Author author)
    {
        try
        {
            book.AddAuthor(author);
            book.Price = 100m;
            _repository.Save(book);
            _sessionContainer.Commit();
        }
        finally
        {
            _sessionContainer.Dispose();
        }
        return book;
    }
}

In the UpdateBook method, we add the newly recruited author and updated the price to $100.  We used the SessionContainer that we created in the previous post to commit the changes at the end of the method and dispose the transaction. If there is any error while committing the changes, a call to Dispose() method (as the control always ends up in the finally block) ensures that the transaction is disposed and in the process all the unsaved changes will be lost.

Only hiccup in the above solution is that you will have to inject ISessionContainer into all the classes that deal with repository. Furthermore, you will have to repeat the same lines of code to commit the changes and dispose the transaction object in all the methods that update the repository. This puts the onus on developer not to forget to add these lines of code in all the methods.

The next step would be to isolate this responsibility so that developer doesn’t have to deal with committing the changes and disposing the transaction.  In the next post we will implement a small console application that tackles this issue. Since Web especially MVC frameworks (ASP.net and Fubu) are so relevant today, we will also discuss how these frameworks handle this seperation of concern.

Written by shashankshetty

October 28, 2009 at 10:11 pm

More FubuMvc features

leave a comment »

In April I blogged on how to set up a simple application using FubuMvc. Today, we will look at more features that I left out in my earlier post. Thanks to Weston Binford for enumerating these changes. Please be aware that Chad Myers is planning to work on several enhancements to the FubuMvc framework including making FubuMvc controller less.

Debug: If you are wondering what is the url that invokes an action, what controllers are these actions part of, what is the method signature, what are its behaviors, how are all these wired up etc, you can find out all the details just by appending __debug to your root url. Please note that it works only on your root directory. For example url for FubuMvcSampleApplcation that is running on cassini web server is http://localhost:2052/__debug that results in the following output.

debug

You can find more details on the Debug feature in this post that was posted on the FubuMVC Development Group.

404 or Page Not Found: To configure a 404 error page we will have to wire up the 404 behavior in our ControllerConfiguration.Configure() method.

x.ActionConventions(convention =&amp;gt;
{
   convention.Add<wire_up_404_handler_URL>();
});

Now we can add a PageNotFoundController with an Index action that takes in a PageNotFoundViewModel and returns the same model back as follows:

public class PageNotFoundController
{
  public PageNotFoundViewModel Index(PageNotFoundViewModel pageNotFoundViewModel)
  {
     return new PageNotFoundViewModel
       {
          Description = "Requested Url not found"
       };
  }
}

public class PageNotFoundViewModel : ViewModel
{
  public string Description { get; set; }
}

It is now time to add a PageNotFound View that displays the description that we populated in our controller.
PageNotFoundView

<asp:Content ID="IndexUser" ContentPlaceHolderID="MainContent" runat="server">
 <%= Model.Description %>. Please check your url.
</asp:Content>

public class PageNotFoundView : FubuMvcSampleApplicationPage&amp;lt;PageNotFoundViewModel&amp;gt;
{
}

Other Url: If you want to call your action with a different url other than the standard url ({controllername}/{actioname}), you can easily override the default behavior for that action in your ControllerConfiguration.Configure() method as shown below:

x.OverrideConfigFor<UserController>(controller => controller.Index(null),
 configuration => configuration.AddOtherUrl("user/List.aspx"));

Now we can reach our Index page with an alternate url user/List.aspx. I have updated the FubuMvcSampleApplication with all the changes discussed in this post that can be downloaded here.

Written by shashankshetty

August 1, 2009 at 7:02 pm

Posted in C#, Fubu Mvc, FubuMvc, Uncategorized

Tagged with , ,

Setting up FubuMVC application on IIS7

leave a comment »

Recently my colleague Weston Binford was trying to set up a FubuMvc application to do a comparison analysis with Asp.net Mvc. He had some issues with running FubuMvcSampleApplication FubuMvc under IIS7. After much debugging he found out that UrlRoutingModule and UrlRoutingHandler must be added under system.webServer tag.

<system.webServer>
 <modules>
 <remove name="UrlRoutingModule" />
 <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
 </modules>
 <handlers>
 <remove name="UrlRoutingHandler" />
 <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
 </handlers>
</system.webServer>

Written by shashankshetty

July 29, 2009 at 10:32 am

Posted in C#, Fubu Mvc, FubuMvc, Uncategorized

Tagged with , ,

Switch between View Result and Json Result without sweat in FubuMVC

with 3 comments

Kazi Manzur Rashid wrote a great post on Adaptive Rendering in ASP.net MVC that is used to return the result based on the request using the same action method. The clear advantage here is that you avoid duplicating your code in the action method just to cater to different request types (like ViewResult, JsonResult).

Chad Myers recently added a feature to FubuMVC that makes adaptive rendering seamless. We will continue to use FubuMvcSampleApplication to demonstrate this feature. First let us add the action convention wire_up_JSON_URL and behaviour output_as_json_if_requested to ControllerConfiguration.Configure() method that is called from our BootStrapper class. Adding wire_up_JSON_URL will simply add another URL (*.json) for every action. For example, if we have a save action, this will add another url save.json during the setup. Now our action responds to url save as well as save.json. output_as_json_if_requested overrides the conventional result and displays a Json result if it is a Json request.

// Action conventions
x.ActionConventions(convention =>
 convention.Add<wire_up_JSON_URL>());

// Default behaviour for all actions
x.ByDefault.EveryControllerAction(action =>
 action.Will<execute_the_result>());

// add a behaviour to output as Josn if it is a json request
x.ByDefault.EveryControllerAction(action =>
 action.Will<output_as_json_if_requested>());

We will now go ahead and implement our action method. For simplicity sake, we will implement a Display action that simply returns UserDetails for the given UserId. Let us add a small piece in action method for the sake of demonstration that populates the Message with either Json Result or View Result based on where the request is coming from.

public UserEditViewModel Display(UserEditViewModel userEditViewModel)
{
  User user = _userRepository.GetUser(userEditViewModel.UserId);
  return new UserEditViewModel(user)
  {
    Message = userEditViewModel.IsAjaxRequest() ? "Json Result" : "View Result"
  };
}

Now let us add a view Display.aspx to demonstrate this feature.

<%= this.FormFor((UserController controller) => controller.Display(null))%>
<div>
 <fieldset>
 <legend>User Details</legend>

Enter john_doe or user2

 <%= this.TextBoxFor(user => user.UserId).ElementId("UserId").Required().WithLabel("UserId")%>
 <input type="button" id="DisplayUsingJson" name="DisplayUsingJson" value = "Display Details Using Json" />                    
 <%= this.SubmitButton("Display", "Display").Class("button") %>

 <%= this.TextBoxFor(user => user.LastName).ElementId("LastName").ReadOnly().WithLabel("Last Name") %>

 <%= this.TextBoxFor(user => user.FirstName).ElementId("FirstName").ReadOnly().WithLabel("First Name") %>                    

 </fieldset></div>
</form>

Enter a user_id and click on Display button to display user details using default behaviour (View Result).

ViewResult

Add the following javascript (uses jquery) that is fired when a user clicks on Display Details using Json button.

function Display() {
 var user = {};
 user.UserId = $("#UserId").val();

 $.getJSON("Display.json", user, function(user) {
 $("#LastName").val(user.LastName);
 $("#FirstName").val(user.FirstName);
 $("#message").html(user.Message);
 });
};

Clicking on Display Details using Json button calls the action method Display using the other url “Display.json” that is used by Fubu to identify where the request is coming from.

JsonResult

We just saw how easy it is to switch between JsonResult or ViewResult. It is features like these, that make FubuMvc a very effective and powerful alternative to ASP.net MVC. I have added the above feature to FubuMVCSampleApplication project and you can download the source code here.

Written by shashankshetty

May 25, 2009 at 7:20 pm

Simple application using FubuMVC

with 7 comments

This is my first effort to use Fubu Mvc. My goal here is not to write a complete or well written application but rather build a simple application that uses different features provided by fubu. Again this post only covers a small percentage of what Fubu offers. Like any open source project Fubu Mvc is being continuously refined and new features are added regularly. In this post, I will be assuming that you know how to get started with Fubu Mvc web project. If you are not familiar with Fubu Mvc, please check out my earlier post on how to get started with Fubu Mvc.

For this post I have built a simple web application that stores a list of users that can be edited or deleted. You can add new users to the list. A sample screenshot of Index.aspx is given below:

userslist

Add New/Edit screen (Edit.aspx) is as shown below:

useredit

To make things easier to understand, here is my project structure.

projectstructure

Now that we have a goal in our mind, let us start with setting up our basic controller behavior in Configure() method in Controller Configuration class. Alternatively, you can also configure the behaviors in Bootstrapper class or Global.asax.

In this method we will do the following:

  • Set up a default behavior for all that actions to display the default view (Ex: Edit action will display an Edit View)
  • Register all the action methods that are in our *Controller classes. In our case it would be UserController.
public class ControllerConfiguration
{
	public static void Configure()
	{
		ControllerConfig.Configure = x =>
		 {
			 // Action conventions
			 x.ActionConventions(convention =>
				 {
					 convention.Add<wire_up_404_handler_URL>();
				 });

			 x.ByDefault.EveryControllerAction(action =>
			   {
				   // Default behaviour for all actions
				   action.Will<execute_the_result>();
			   });

			 //Automatic controller registration
			 x.AddControllerActions(
				 assembly => assembly.UsingTypesInTheSameAssemblyAs<ViewModel>(
								 types =>
								 types.SelectTypes(
									 type => type.Namespace.EndsWith("Controllers")
											 && type.Name.EndsWith("Controller"))));

			 // Override default behaviours defined above
			 // We will override certain behaviors to suit our actions - details are discussed further in the post
		 };
	}
}

Now that we are through with setting up the default behavior for all our controller actions, let us go ahead and write our controller methods (or actions). Our Index method is straight forward, that queries the users from a repository and wraps it in a UserListViewModel containing a list of UserDisplayModels (User details needed to display on the web page).

public UserListViewModel Index(UserIndexViewModel userIndexViewModel)
{
	return new UserListViewModel
	   {
		   Users = _userRepository.GetUsers().Select(user => new UserDisplayModel(user)),
	   };
}

// Models needed for the Index method
public class ViewModel
{
        public string Message { get; set; }
}

public class UserIndexViewModel : ViewModel
{
}

public class UserListViewModel : ViewModel
{
	public IEnumerable Users { get; set; }
}

Index View is rather straightforward that loops over each of the UserDisplayModels and displays its properties:

<%= this.FormFor<UserController>(controller => controller.Index(null)) %>
<div>
	<fieldset>
		<legend>List Users</legend>
<div id="Navigate"><a href="/user/new">Add New</a></div>
<table id = "listTable">
<thead>
<tr>
<th>UserId</th>
<th>LastName</th>
<th>FirstName</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
			<% foreach(var model in Model.Users) {%>
<tr>
<td><%= model.UserId%></td>
<td><%= model.LastName %></td>
<td><%= model.FirstName %></td>
<td><a href="<%= this.UrlTo().EditUser(model.UserId) %>">Edit</a></td>
<td><a href="<%= this.UrlTo().DeleteUser(model.UserId) %>">Delete</a></td>
</tr>
<% } %></tbody></table>
</fieldset></div>
</form>

Now let us go ahead and implement Edit action in our UserController that takes in a UserEditViewModel containing atleast a UserId and returns UserEditViewModel with all the User details filled in.

public UserEditViewModel Edit(UserEditViewModel userEditViewModel)
{
	User user = _userRepository.GetUser(userEditViewModel.UserId);
	return new UserEditViewModel(user);
}

public class UserEditViewModel : ViewModel
{
	public UserEditViewModel()
	{
	}

	public UserEditViewModel(User user)
	{
		if (user == null) return;
		UserId = user.UserId;
		LastName = user.LastName;
		FirstName = user.FirstName;
		DateOfBirth = user.DateOfBirth != null ? user.DateOfBirth.Value.ToShortDateString(): null;
	}

	public string UserId { get; set; }
	public string LastName { get; set; }
	public string FirstName { get; set; }
	public string DateOfBirth { get; set; }
}

Edit View that displays the user details is as follows:

<%= this.FormFor((UserController controller) => controller.Cancel(null))%>
<div>
<fieldset>
<legend>Add/Edit User</legend>

<%= this.TextBoxFor(user => user.UserId).ElementId("UserId").Required().WithLabel("UserId")%>

<%= this.TextBoxFor(user => user.LastName).ElementId("LastName").WithLabel("Last Name") %>

<%= this.TextBoxFor(user => user.FirstName).ElementId("FirstName").WithLabel("First Name")%>

<%= this.TextBoxFor(user => user.DateOfBirth).ElementId("DateOfBirth").WithLabel("Date of Birth") %>

<input type="button" id="Save" name="Save" value = "Save" class="button" />
<%= this.SubmitButton("Cancel", "Cancel").Class("button") %>

</fieldset></div>
</form>

Now that we have taken care of Index and Edit views that have its own views, let us see if we can implement Add New User – New and Delete features using the views that we already have.

Let us go ahead and implement the New method.

public UserEditViewModel New(UserEditViewModel userEditViewModel)
{
	return new UserEditViewModel();
}

Ideally this would look for a New view. Since we don’t have a New view, we will see if we can re-use our Edit view (To display a New User page, we just have to blank the form fields that is used in Edit meaning it has the same signature as Edit View). We can do this by overriding the default behavior of New method and make it to use Edit View just by adding the following code in our ControllerConfiguration.Configure() method.

 x.OverrideConfigFor(controller =>
	 controller.New(null), configuration =>
	   configuration.UseViewFrom((UserController c) =>
			c.Edit(null)));

This is similar to displaying a different view from an action in ASP.net Mvc [return new View(“New”)].

Now let us go ahead and implement Delete that displays a success/error message based on the operation.

public UserListViewModel Delete(UserEditViewModel userEditViewModel)
{
	User user = _mapper.MapFrom(userEditViewModel);
	string message;
	try
	{
		_userRepository.Delete(user);
		message = String.Format("User {0} successfully deleted", user.UserId);
	}
	catch (ArgumentException exception)
	{
		message = String.Format("User {0} could not be deleted: {1}", user.UserId, exception.Message);
	}
	UserListViewModel usersListViewModel = GetUsers();
	usersListViewModel.Message = message;
	return usersListViewModel;
}

After the Delete operation is performed, we want it to use the View from Index, so let us go ahead and add this behaviour in our ControllerConfiguration.Configure() method.

 x.OverrideConfigFor(controller =>
	 controller.Delete(null), configuration =>
	   configuration.UseViewFrom((UserController c) =>
			c.Index(null)));

Next, let us implement Save that saves or updates the user and displays a success message. It displays an error message if the UserId is blank or the user cannot be saved.

public UserEditViewModel Save(UserEditViewModel userEditViewModel)
{
	if (String.IsNullOrEmpty(userEditViewModel.UserId))
	{
		userEditViewModel.Message = String.Format("UserId cannot be blank");
		return userEditViewModel;
	}
	User user = _mapper.MapFrom(userEditViewModel);
	try
	{
		_userRepository.Save(user);
		userEditViewModel.Message = "User saved successfully";
	}
	catch (Exception exception)
	{
		userEditViewModel.Message = String.Format("User could not be saved: {0}", exception.Message);
	}
	return userEditViewModel;
}

Now the question is how do we display the success/error message (userEditViewModel.Message) on the screen. Let us say we want to use Json, Fubu makes it as easy as possible. No more tying up your controller to return Json (as in ASP.net mvc). Our Controller action can be totally unaware of whether we use Json or anything else to display the message. This can be controlled from outside in ControllerConfiguration.Configure() method.

To output as Json add the following line of code to your ControllerConfiguration.Configure() method.

 x.OverrideConfigFor(controller =>
	 controller.Save(null), configuration =>
	   configuration.AddBehavior());

Now let us go ahead and implement our last remaining action “Cancel” that redirects us from Edit to Index page.  To redirect to a different action, use IResultOverride that is injected into the controller.

public UserIndexViewModel Cancel(UserEditViewModel userEditViewModel)
{
	_resultOverride.RedirectTo(_urlResolver.UrlFor<UserController>());
        return new UserIndexViewModel();
}

Cancel method takes in a UserEditViewModel and outputs a UserIndexViewModel. To redirect, pass in the url for the action that you want to redirect. Index being the default, the above method redirects to Index action. This is similar to RedirectToAction in ASP.net Mvc.

public class UserIndexViewModel : ViewModel
{
}

One thing to note here is our controller methods are really easy to test as they take in a model and return a model. Also, our controller methods are totally unaware of whether we output as Json or use a different view as they are controlled from outside. Just like scenes in a movie can be shot in any order, but editing puts all the scenes in a chronological order and we can have theatrical version and a DVD version, we can write our controller methods and wire them up outside in ControllerConfiguration.Configure() method. We can also decide whether we want to output as Json or use another view etc. You can download the source code for the sample application here.

public class ControllerConfiguration
{
public static void Configure()
{
ControllerConfig.Configure = x =>
{
// Action conventions
x.ActionConventions(convention =>
{
convention.Add<wire_up_JSON_URL>();
convention.Add<wire_up_404_handler_URL>();
});x.ByDefault.EveryControllerAction(action =>
{
// Default behaviour for all actions
action.Will<execute_the_result>();
// add a behaviour to output as Json if it is a json request
action.Will<output_as_json_if_requested>();
});//Automatic controller registration
x.AddControllerActions(
assembly => assembly.UsingTypesInTheSameAssemblyAs<ViewModel>(
types =>
types.SelectTypes(
type => type.Namespace.EndsWith(“Controllers”)
&& type.Name.EndsWith(“Controller”))));

// Override default behaviours defined above
x.OverrideConfigFor<UserController>(controller =>
controller.New(null),
configuration =>
configuration.UseViewFrom(
(UserController c) =>
c.Edit(null)));

x.OverrideConfigFor<UserController>(controller =>
controller.Delete(null),
configuration =>
configuration.UseViewFrom(
(UserController c) =>
c.Index(null)));

x.OverrideConfigFor<UserController>(controller =>
controller.Save(null),
configuration =>
configuration.AddBehavior
<OutputAsJson>());
};
}
}

Written by shashankshetty

April 13, 2009 at 6:09 pm

Posted in C#, Fubu Mvc, FubuMvc, Uncategorized

Tagged with , ,

Fubu MVC

with one comment

Fubu (For us, by us) MVC is an alternative to ASP.net MVC framework and is a front controller style framework.  If you are interested in digging into details of fubu, these links can help you get started.

Written by shashankshetty

April 12, 2009 at 6:23 pm

Posted in C#, Fubu Mvc, FubuMvc, Uncategorized

Tagged with , ,

Follow

Get every new post delivered to your Inbox.