After Thought

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>());
};
}
}

About these ads

Written by shashankshetty

April 13, 2009 at 6:09 pm

Posted in C#, Fubu Mvc, FubuMvc, Uncategorized

Tagged with , ,

7 Responses

Subscribe to comments with RSS.

  1. [...] to VoteSimple application using FubuMVC (4/13/2009)Monday, April 13, 2009 from shashankshettyThis is my first effort to use Fubu Mvc. My goal here is [...]

  2. Simple application using FubuMVC « Shashank’s Blog…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

    DotNetShoutout

    May 11, 2009 at 3:29 pm

  3. Простое приложение на FubuMVC…

    Thank you for submitting this cool story – Trackback from progg.ru…

    progg.ru

    May 11, 2009 at 11:44 pm

  4. [...] 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 [...]

  5. [...] Simple application using FubuMVC – Introduction by Shashank [...]

  6. [...] Mvc, FubuMvc, Uncategorized | Tags: C#, Fubu Mvc, FubuMvc | 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 [...]

  7. [...] mentioned that there is no need for a controller to know about the underlying framework. However, in an example on someone’s blog, the following code is used. (Or perhaps we could link to a latest recipe which used the latest [...]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: