MVC

ASP.NET MVC and Kendo UI Grid

0

A grid provides a common presentation to represent a collection of data, which is a table containing rows and columns. Although creating this experience is not difficult, the features to deliver a quality user experience will require a significant investment. The alternative is a widget library, which provides advanced features requiring minimal effort.

In this post, I will demonstrate a few features of the Kendo UI Grid, which is one of many widgets included in the Kendo UI products. After several years of experience with Telerik products, the next generation Kendo UI is HTML5 and CSS3. I also elected to include the Kendo UI Complete, which packages convenient server extensions for the JavaScript framework. You can learn more about the products and better understand the licensing, which is a huge obstacle for many budget conscious organization. And yes…many alternatives exist including the JQuery.UI library.

Kendo UI provides a handy Visual Studio plugin, which can convert and prepare projects for Kendo UI. I converted an existing ASP.NET MVC4 project, which saves several manual steps. I was also able to select one of the Kendo themes, which will be applied to all Kendo widgets.

You can read several of my previous posts, which discuss design patterns to build enterprise applications. In this article, my goal is to provide a quick start for the Kendo UI Grid implementation. So…I will not create a fully functioning repository, but instead a static memory based to provide the basics for the demonstration.

I will modify the standard ASP.NET MVC4 starter project and add a new menu option called Contacts. This will require a controller, view model and service - all the basics. We’ll start with a simple read-only grid, which will display the current contacts with paging, filtering and sorting features. The following is the read-only Contacts grid.

Contacts Read-Only Grid

The grid is a table containing the Name, Mode of Contact, Phone and Email columns. The sort, filter and paging features are enabled, so the user can interact with the grid and data using several helpful options. So…let’s look at the view containing the grid configuration.

 C# |  copy code |? 
01
@using MvcKendoUIGrid.Models
02
 
03
@(Html.Kendo().Grid<Contact>()
04
      .Name("contactGrid")
05
      .Columns(columns =>
06
 
07
          {
08
               columns.Bound(c => c.Name).Title("Name").Width(150);
09
              columns.Bound(c => c.PreferredContactMode).Title("Mode of Contact").Width(150);
10
              columns.Bound(c => c.Phone).Title("Phone").Width(120);
11
              columns.Bound(c => c.Email).Title("Email").Width(120);
12
          })
13
      .Pageable()
14
      .Filterable()
15
      .Sortable()
16
      .Scrollable()
17
      .AutoBind(true)
18
      .HtmlAttributes(new {style = "height:250px;"})
19
      .DataSource(dataSource => dataSource
20
                                    .Ajax()
21
                                    .ServerOperation(false)
22
                                    .Model(model =>
23
                                        {
24
                                            model.Id(c => c.Id);
25
                                            model.Field(c => c.PreferredContactMode).Editable(true).DefaultValue(new ContactMode {Id = 0, Name = string.Empty});
26
                                        })
27
                                    .Read(read => read.Action("Read", "Contact"))
28
)      )

The Pageable, Sortable, Filterable and Scrollable provide the advanced grid features with just one line of code. The DataSource defines the data and actions to read. The model is the Contact, so the fields and id are defined. The Read action is an ajax call to the Contact controller and Read method, which will return a collection of Contact objects. The Columns define the layout of columns, headers and binding to the model.

The Contact model contains the Id, NamePhone and Email properties. It also includes the ContactMode, which is a complex object including an Id and Name. We’ll see more on the complex object in the next section.

 C# |  copy code |? 
01
using System.Collections.Generic;
02
using System.Web.Mvc;
03
using Kendo.Mvc.Extensions;
04
using Kendo.Mvc.UI;
05
using MvcKendoUIGrid.Models;
06
using MvcKendoUIGrid.Services;
07
 
08
namespace MvcKendoUIGrid.Controllers
09
{
10
    /// <summary>
11
    /// Contact controller providing support for views
12
    /// </summary>
13
    public class ContactController : Controller
14
    {
15
        private readonly IContactService _service;
16
 
17
        /// <summary>
18
        /// Default Constructor
19
        /// </summary>
20
        public ContactController()
21
        {
22
            _service = new ContactService();
23
        }
24
 
25
        /// <summary>
26
        /// Default action to render Contact grid
27
        /// </summary>
28
        /// <returns></returns>
29
        public ActionResult Index()
30
        {
31
            TempData["ContactMode"] = new List<ContactMode>
32
                {
33
                    new ContactMode {Id = 1, Name = "Phone"},
34
                    new ContactMode {Id = 2, Name = "Email"}
35
                };
36
 
37
            return View();
38
        }
39
 
40
        /// <summary>
41
        ///     Read action to populate grid
42
        /// </summary>
43
        /// <param name="dsRequest">Kendo Datasource Request</param>
44
        /// <returns>ActionResult</returns>
45
        [HttpPost]
46
        public ActionResult Read([DataSourceRequest] DataSourceRequest dsRequest)
47
        {
48
            try
49
            {
50
                return Json(_service.GetAllContacts().ToDataSourceResult(dsRequest));
51
            }
52
            catch
53
            {
54
                ModelState.AddModelError("Contacts", "Unable to load contacts.");
55
                return Json(ModelState.ToDataSourceResult());
56
            }
57
        }
58

The Index action is called on the initially, which will save the possible ContactMode selections as TempData. The Read action invokes the service GetAllContacts method to return a collection of Contacts.

The next step is providing the ability to edit the contacts. The following is the revised view, which includes the changes to enable editing.

 C# |  copy code |? 
01
@using MvcKendoUIGrid.Models
02
 
03
@(Html.Kendo().Grid<Contact>()
04
      .Name("contactGrid")
05
      .Columns(columns =>
06
 
07
          {
08
              columns.Command(command =>
09
                  {
10
                      command.Edit();
11
                   }).Width(180);
12
              columns.Bound(c => c.Name).Title("Name").Width(150);
13
              columns.Bound(c => c.PreferredContactMode).Title("Mode of Contact").Width(150);
14
              columns.Bound(c => c.Phone).Title("Phone").Width(120);
15
              columns.Bound(c => c.Email).Title("Email").Width(120);
16
          })
17
      .Pageable()
18
      .Filterable()
19
      .Sortable()
20
      .Scrollable()
21
      .AutoBind(true)
22
      .HtmlAttributes(new {style = "height:250px;"})
23
      .Editable(ed => ed.Mode(GridEditMode.InLine))
24
      .DataSource(dataSource => dataSource
25
                                    .Ajax()
26
                                    .ServerOperation(false)
27
                                    .Model(model =>
28
                                        {
29
                                            model.Id(c => c.Id);
30
                                            model.Field(c => c.PreferredContactMode).Editable(true).DefaultValue(new ContactMode {Id = 0, Name = string.Empty});
31
                                        })
32
                                    .Read(read => read.Action("Read", "Contact"))
33
                                    .Update(update => update.Action("Edit", "Contact"))
34
      )
35
      )

The DataSource now includes the Update, which calls the Contact controller Edit method. The Editable supports inline and popup edit modes, so we will select inline to allow editing within the grid. We also add a column command, which injects the edit button in the first column. We also add the Edit method to the controller, which is responsible for calling the service to update the contract.

 C# |  copy code |? 
01
        /// <summary>
02
        /// Edit action to update existing contact
03
        /// </summary>
04
        /// <param name="dsRequest">Kendo Datasource Request</param>
05
        /// <param name="viewmodel">Contact model containing values to update</param>
06
        /// <returns>ActionResult</returns>
07
        [HttpPost]
08
        public ActionResult Edit([DataSourceRequest] DataSourceRequest dsRequest, Contact viewmodel)
09
        {
10
            try
11
            {
12
                if (ModelState.IsValid && viewmodel != null)
13
                    _service.Update(viewmodel);
14
                else //model error
15
                    ModelState.AddModelError("Contacts", "Unable to edit contact - not a valid contact.");
16
            }
17
            catch
18
            {
19
                ModelState.AddModelError("Contacts", "Unable to edit contact.");
20
            }
21
 
22
            return Json(ModelState.ToDataSourceResult());
23
        }
24

If we test the changes then we see the addition of the edit button. Clicking the edit button will allow the editing of the selected row.

Contact Grid Edit

You will notice the Mode of Contact column displays the Id and Name textbox, which is not the best experience for selecting the contact mode.

Contact Grid Edit Complex Object

Since ContactMode is a complex object, the editor includes the Id and Name. We would like to provide a dropdown list of available contact modes, so the user must select a valid option. We previously saved a collection of ContactMode objects representing the valid options in the TempData, so this will be the dropdown list source. The solution is creating a new editor for the ContactMode type, so when the correct editor is presented. The following is the ContactMode editor, which should be added to the Shared Editor Templates folder.

 C# |  copy code |? 
1
@model MvcKendoUIGrid.Models.ContactMode
2
@(Html.Kendo().DropDownList()
3
      .Name("PreferredContactMode")
4
      .BindTo((System.Collections.IEnumerable)TempData["ContactMode"])
5
      .OptionLabel("Select a Mode")
6
      .DataTextField("Name")
7
      .DataValueField("Id")
8
      .HtmlAttributes(new { required = true })
9
      )

We are using the Kendo UI DropDownList widget, which is a dropdown list. The BindTo is the list data source, which is referencing the TempData we populated in our initial Index method. The DataTextField and DataValueField are the value and text property names. We also set the required attribute, which ensures the contact mode is required. It is important to note the Name must be the name of the grid model property, so the two-way binding is correct. Let’s see the results of the changes to the edit mode.

Contacts Grid Edit Dropdown

The final features are Add and Delete. The following is the view containing the updates for Add and Delete. You will also notice the ClientTemplate applied to the ContactMode, which forces the view to include the Name property in the display.

 C# |  copy code |? 
01
@using MvcKendoUIGrid.Models
02
 
03
@(Html.Kendo().Grid<Contact>()
04
      .Name("contactGrid")
05
      .Columns(columns =>
06
 
07
          {
08
              columns.Command(command =>
09
                  {
10
                      command.Edit();
11
                      command.Destroy();
12
                  }).Width(180);
13
              columns.Bound(c => c.Name).Title("Name").Width(150);
14
              columns.Bound(c => c.PreferredContactMode).Title("Mode of Contact").ClientTemplate("#=PreferredContactMode.Name#").Width(150);
15
              columns.Bound(c => c.Phone).Title("Phone").Width(120);
16
              columns.Bound(c => c.Email).Title("Email").Width(120);
17
          })
18
      .ToolBar(toolbar => toolbar.Create().Text("Add new contact"))
19
      .Pageable()
20
      .Filterable()
21
      .Sortable()
22
      .Scrollable()
23
      .AutoBind(true)
24
      .HtmlAttributes(new {style = "height:250px;"})
25
      .Editable(ed => ed.Mode(GridEditMode.InLine))
26
      .DataSource(dataSource => dataSource
27
                                    .Ajax()
28
                                    .ServerOperation(false)
29
                                    .Model(model =>
30
                                        {
31
                                            model.Id(c => c.Id);
32
                                            model.Field(c => c.PreferredContactMode).Editable(true).DefaultValue(new ContactMode {Id = 0, Name = string.Empty});
33
                                        })
34
                                    .Read(read => read.Action("Read", "Contact"))
35
                                    .Update(update => update.Action("Edit", "Contact"))
36
                                    .Destroy(delete => delete.Action("Delete", "Contact"))
37
                                    .Create(create => create.Action("Create", "Contact"))
38
      )
39
      )

We add the Destroy to the command, which provides the Delete button. The DataSource Destroy defines the Contact controller delete action, which will be responsible for deleting the contact. We add the create command to the Toolbar, which is positioned above the grid. The DataSource Create is the action invoked when the “Add new contact” button is clicked.

The Create and Delete controller methods appear below.

 C# |  copy code |? 
01
        /// <summary>
02
        /// Create action to add new contact
03
        /// </summary>
04
        /// <param name="dsRequest">Kendo Datasource Request</param>
05
        /// <param name="viewmodel">Contact model containing values to add</param>
06
        /// <returns>ActionResult</returns>
07
        [HttpPost]
08
        public ActionResult Create([DataSourceRequest] DataSourceRequest dsRequest, Contact viewmodel)
09
        {
10
            try
11
            {
12
                if (ModelState.IsValid && viewmodel != null)
13
                {
14
                    _service.Add(viewmodel);
15
                    return Json(new[] {viewmodel}.ToDataSourceResult(dsRequest, ModelState));
16
                }
17
                ModelState.AddModelError("Contacts", "Unable to add contact - not a valid contact.");
18
            }
19
            catch
20
            {
21
                ModelState.AddModelError("Contacts", "Unable to add contact.");
22
            }
23
 
24
            return Json(ModelState.ToDataSourceResult());
25
        }
26
 
27
        /// <summary>
28
        /// Delete action to remove existing contact
29
        /// </summary>
30
        /// <param name="dsRequest">Kendo Datasource Request</param>
31
        /// <param name="viewmodel">Contact model containing values to delete</param>
32
        /// <returns>ActionResult</returns>
33
        [HttpPost]
34
        public ActionResult Delete([DataSourceRequest] DataSourceRequest dsRequest, Contact viewmodel)
35
        {
36
            try
37
            {
38
                if (viewmodel != null)
39
                    _service.Delete(viewmodel);
40
                else
41
                    ModelState.AddModelError("Contacts", "Unable to delete contact - not a valid contact.");
42
            }
43
            catch
44
            {
45
                ModelState.AddModelError("Contacts", "Unable to delete contact.");
46
            }
47
 
48
            return Json(ModelState.ToDataSourceResult());
49
        }
50

The final version with the Edit, Add and Delete actions enabled.

Contacts Grid Complete

Contacts Grid AddContacts Grid Delete

I hope this provides a quick overview of the Kendo UI Grid widget and Kendo UI MVC server extensions, which together provide powerful features with minimal effort.

Castle Windsor IoC and AOP with ASP.NET MVC 4

0

It is no secret that I am a huge supporter of IoC (Inversion of Control) and AOP (Aspect-oriented Programming), which is evident with several earlier posts focused on building Enterprise applications. My first IoC experience was a Java portal project, which implemented Spring for many enterprise services. My recent projects have been .NET, which include several Spring.NET and Castle implementations. When evaluating IoC products, Ninject and more recently Microsoft Unity have also been candidates. IoC is gaining Microsoft community acceptance, especially with the release of ASP.NET MVC 4 and improved support/integration. See previous article for more information on design patterns including Dependency Injection (DI), Single Responsibility Principle (SRP) and Separation of Concerns (SoC).

In this post, I will provide an overview of the MVC 4 Castle Windsor IoC and Castle Core Dynamic Proxy features. Gasp…after several articles and posts with Spring.NET? This is true, but every project should evaluate several IoC (also referred to as Dependency Injection) containers and select the one that fits.

I would recommend NuGet for packages, so you can simplify the management of 3rd party libraries and tools.

Once you create a new ASP.NET MVC 4 solution and add the Castle packages to your solution, we can start building the application framework and scaffolding. Since this is a quick-start for Castle IoC and AOP features, we’ll build the essential components for a working MVC 4 solution.

First, create a Framework folder for the IoC and AOP classes. I would recommend Framework or Core, which are descriptive names. I created a Windsor sub-folder, which indicates the items will be supporting the IoC and AOP. The next level is Installers and Interceptors at the same level, so the following is an example of the project structure.

Framework Folder Structure

First, we will create the boilerplate WindsorControllerFactory to handle the IoC plumbing. The following is a snippet of the code, which you can add to the Framework.Windsor folder.

01
using System;
02
using System.Web;
03
using System.Web.Routing;
04
using Castle.MicroKernel;
05
using System.Web.Mvc;
06
 
07
namespace Mvc4Castle.Framework.Windsor
08
{
09
    /// <summary>
10
    /// Castle Windsor MVC4 Controller Factory Implementation for IoC
11
    /// </summary>
12
    public class WindsorControllerFactory : DefaultControllerFactory
13
    {
14
        private IKernel _kernel;
15
 
16
        public WindsorControllerFactory(IKernel kernel)
17
        {
18
            _kernel = kernel;
19
        }
20
 
21
        public override void ReleaseController(IController controller)
22
        {
23
            _kernel.ReleaseComponent(controller);
24
        }
25
 
26
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
27
        {
28
            if (controllerType == null)
29
            {
30
                throw new HttpException(404, string.Format("The Windsor Controller at path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
31
            }
32
            return (IController)_kernel.Resolve(controllerType);
33
        }
34
    }
35
}

Next, we will create IWindsorInstaller implementations. The installers will register components or objects with the IoC container. Alternatively, you can choose XML-based configuration files to define the components/objects instructing the container on the “How” to instantiate. In our example, we will use the MVC controllers included in the starter project (e.g. HomeController).

01
using Castle.MicroKernel.Registration;
02
using Castle.Windsor;
03
using Castle.MicroKernel.SubSystems.Configuration;
04
using System.Web.Mvc;
05
using Mvc4Castle.Controllers;
06
 
07
namespace Mvc4Castle.Framework.Windsor.Installers
08
{
09
    /// <summary>
10
    /// Castle Windsor Controller responsible for registering classes managed by
11
    /// the IoC container.
12
    /// 
13
    /// This implementation registers all MVC Controllers (IController).
14
    /// </summary>
15
    public class ControllerInstaller : IWindsorInstaller
16
    {
17
        public void Install(IWindsorContainer container, IConfigurationStore store)
18
        {
19
            container.Register(Classes.FromThisAssembly()
20
                                .BasedOn<IController>()
21
                                .LifestyleTransient()
22
                                .ConfigureFor<HomeController>(c => c.DependsOn(Dependency.OnComponent("service", "MyServiceResource"))));
23
        }
24
    }
25
}

In this example, we are registering objects/components based on IController located in the current assembly. We are also configuring the HomeController and dependency injection of the service argument. We’ll explore additional options for registering objects/components in the container.

We also need to add the container to our start-up processes in the global.asax. The Application_Start and Application_End require some logic to handle this task.

01
    public class MvcApplication : System.Web.HttpApplication
02
    {
03
        private static IWindsorContainer _container;
04
 
05
        protected void Application_Start()
06
        {
07
            AreaRegistration.RegisterAllAreas();
08
 
09
            WebApiConfig.Register(GlobalConfiguration.Configuration);
10
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
11
            RouteConfig.RegisterRoutes(RouteTable.Routes);
12
            BundleConfig.RegisterBundles(BundleTable.Bundles);
13
            InjectContainer();
14
        }
15
 
16
        /// <summary>
17
        /// Create MVC4 Controller for Castle Windsor IoC container
18
        /// </summary>
19
        private static void InjectContainer()
20
        {
21
            _container = new WindsorContainer().Install(FromAssembly.This());
22
 
23
            var controllerFactory = new WindsorControllerFactory(_container.Kernel);
24
            ControllerBuilder.Current.SetControllerFactory(controllerFactory);
25
        }
26
 
27
        /// <summary>
28
        /// Destroy Castle Windsor IoC container
29
        /// </summary>
30
        protected void Application_End()
31
        {
32
            _container.Dispose();
33
        }
34
    }
35

You can add several installer implementations using the fluent API or XML-based configuration files, so you can organize your object/component definitions for the IoC container. Since we are following design patterns, we will introduce Dependency Injection/DIP practices to inject the object/component dependency via the controller constructor. The service will represent the business logic, which is responsible for orchestrating the calls to the data tier or other service objects to process the client request and return an appropriate result.

1
       private IService _service;
2
 
3
        public HomeController(IService service)
4
        {
5
            _service = service;
6
        }

So…let’s take a look at a few container registration options. The following will register all objects/components with a type ending in “Service” (i.e. wildcard Service) from the current assembly. The life-cycle can also be configured, which in the examples ”transient” indicates a new instance.

1
           container.Register(Classes.FromThisAssembly()
2
                 .Where(type => type.Name.EndsWith("Service"))
3
                 .WithServiceDefaultInterfaces()
4
                 .Configure(c => c.LifestyleTransient().Interceptors<ServiceTitleInterceptor>()));
5

We’ll cover the AOP or dynamic proxies, which is the Interceptor. The following example defines the dependency using a named value, so the “Title” property will be set to the static value “Injected By Dependency Value”.

1
            container.Register(Component.For<IService>()
2
                .ImplementedBy<HomeService>()
3
                .Named("MyServiceValue")
4
                .DependsOn(Dependency.OnValue("Title", "Injected By Dependency Value"))
5
                .LifestyleTransient());
6

The next example is injecting the “Title” property value from the web.config appsettings “Title” parameter.

1
            container.Register(Component.For<IService>()
2
                .ImplementedBy<HomeService>()
3
                .Named("MyServiceConfig")
4
                .DependsOn(Dependency.OnAppSettingsValue("Title", "Title"))
5
                .LifestyleTransient());
6

The following illustrates injecting a property value from a resource file, which also is the “Title” property. This provides several source options for the dependency injection, which can also include a named component (see Named).

1
            container.Register(Component.For<IService>()
2
                .ImplementedBy<HomeService>()
3
                .Named("MyServiceResource")
4
                .DependsOn(Dependency.OnResource<App_LocalResources.Resource1>("Title", "Title"))
5
                .LifestyleTransient());
6

The previous examples introduce the Castle Windsor IoC basics as they apply to MVC4. The last topic is AOP, which we encountered with the interceptor in a previous object/component container registration. The Spring.NET AOP support was introduced in a previous post. Castle core is a lighter version, which is based on implementing the Castle.DynamicProxy.IInterceptor.

01
    public class ServiceTitleInterceptor : IInterceptor
02
    {
03
        public void Intercept(IInvocation invocation)
04
        {
05
            if (invocation.Method.Name.Equals("get_Title"))
06
                invocation.ReturnValue = "You have been hijacked at." + DateTime.Now;
07
            else
08
                invocation.Proceed();
09
        }
10
     }

In this interceptor implementation, the Intercept method contains logic to check for the method name “get_Title”. This is a Title property getter. If true then ReturnValue is set to “You have been hijacked at.” including a date-stamp. If the method name is not “get_Title” then the control is returned to the intercepted object and processing continues. You can implement an interceptor for logging, caching, transaction management, error handling and other common services without adding code to every class and method.

The following is an installer snippet for registering an object/component using the ServiceTitleInterceptor interceptor, so every call will be intercepted and the Intercept method executed.

1
.Interceptors<ServiceTitleInterceptor>()

The above will apply the ServiceTitleInterceptor to the object/component. You can also add the InterceptorAttribute ( [Interceptor(typeof(ServiceTitleInterceptor))] ) to the target class, which is an alternative to the fluent API approach above.

01
using Castle.Core;
02
using Mvc4Castle.Framework.Windsor.Interceptors;
03
 
04
namespace Mvc4Castle.Framework.Services
05
{
06
    [Interceptor(typeof(ServiceTitleInterceptor))]
07
    public class HomeService : IService
08
    {
09
        public string Title { get; set; } 
10
    }
11
}

I hope this quick-start provides another IoC and AOP option for your MVC projects. Since I was evaluating several IoC libraries for a current project, I thought a summary could be helpful.

Related Posts:

Sping.NET IoC

Spring.NET and MVC3

Spring.NET AOP

WCF and Spring.NET

0

In this article, we will demonstrate a WCF implementation using Spring.NET. This will enable us to utilize the IoC container features supporting Dependency Injection, so we can inject the dependencies required to instantiate and initialize the service.

In previous articles, we built POCO (Plain Old CLR Object) services to represent the business tier and slightly more complex objects for the data tier. This is still the recommended architecture for enterprise services when integration and interoperability are not required. A distributed/service oriented design will add overhead and require additional resources to support. If you intend to publish your services for external partners or integrate legacy systems then WCF is a great solution. 

I still recommend separation and building POCO services as discussed under previous articles. A POCO service is far more reusable than a highly decorated and framework dependent object. We can leverage WCF to expose the services to a variety of consumer applications without the burden of building all the plumbing. The following are some common WCF terms.

  • Endpoints – a network resource accessible by clients to communicate based on agreed contracts.
  • Bindings – the how to communicate with the endpoint. The lowest level is the transport to exchange messages over the network. The built-in transports include HTTP, TCP, Names Pipes and MSMQ. The parent levels include security and transactions.
  • Contracts – the contracts define the features exposed by the endpoint, which includes the message/data format and operations.
Contracts

The first step is create the service contract, which defines the service operations. The simplest approach is mark your service interface class with the ServiceContract attribute and the operation methods with the OperationContract attribute. In the example below, we decorated the IContactsService class with the appropriate attributes for a service contract.

01
using Joemwalton.ContactManager.Common.Model;
02
namespace Joemwalton.ContactManager.Common.Services
03
{
04
    [ServiceContract]
05
    public interface IContactsService
06
    {
07
        [OperationContract]
08
        void DeleteContact(int id);
09
        [OperationContract]
10
        Contact GetContact(int id);
11
        [OperationContract]
12
        IList<Contact> GetContacts();
13
        [OperationContract]
14
        int SaveContact(Contact contact);
15
    }
16
}

The above class will expose the DeleteContact, GetContact, GetContacts and SaveContact operations. The next step is defining the Data Contracts. The DataContract attribute will mark the classes that represent the message/data format for the operations. The Data Contract will instruct the framework to represent the marked items as an XSD, which is included in the WSDL exposed for consumers discovery. The DataMember attribute identifies the included class members.

Alternatively, types marked with the Serializable attribute and members not marked with NonSerialized will be serialized. The default DataContactSerializer will also serialize types and generate the WSDL for all CLR primitives (e.g. int32, string), arrays, collections and enumerations. Please see the Microsoft documentation for additional types supported by the serializer. In our example, we will add Serializable to the Contact class and leverage the supported primitives.

01
namespace Joemwalton.ContactManager.Common.Model
02
{
03
    [Serializable]
04
    public abstract class ModelBase
05
    {
06
        public virtual bool IsValid
07
        {
08
            get { return true; }
09
        }
10
    }
11
}
12
 
13
namespace Joemwalton.ContactManager.Common.Model
14
{
15
    /// <summary>
16
    /// Contact domain object
17
    /// </summary>
18
    ///
19
    [Table(Name="Contacts")]
20
    public class Contact : ModelBase
21
    {
22
 
23
        public Contact() { }
24
 
25
        public Contact(string name,
26
                       string emailAddress,
27
                       string mobilePhone)
28
        {
29
            Name = name;
30
            EmailAddress = emailAddress;
31
            MobilePhone = mobilePhone;
32
        }
33
 
34
        public Contact(int id,
35
                       string name,
36
                       string emailAddress,
37
                       string mobilePhone)
38
        {
39
            Id = id;
40
            Name = name;
41
            EmailAddress = emailAddress;
42
            MobilePhone = mobilePhone;
43
        }
44
 
45
        public Contact(int id,
46
                       string name,
47
                       string emailAddress,
48
                       string mobilePhone,
49
                       byte[] picture)
50
        {
51
            Id = id;
52
            Name = name;
53
            EmailAddress = emailAddress;
54
            MobilePhone = mobilePhone;
55
            Picture = picture;
56
        }
57
 
58
        private int _Id = -1;
59
        public int Id 
60
        {
61
            get { return _Id; }
62
            set { _Id = value; }
63
        }
64
 
65
        public string Name { get; set; }
66
 
67
        public string EmailAddress { get; set; }
68
 
69
        public string MobilePhone { get; set; }
70
 
71
        public byte[] Picture { get; set; }
72
 
73
        public override bool IsValid
74
        {
75
            get { return true; }
76
        }
77
     }
78
}
79

WCF Service

The next step is implementing the service, which as we discussed previously will be a wrapper exposing our concrete service. The following is the ContactsService concrete implementation, which is the same POCO service we are using for other enterprise applications.

01
using Joemwalton.ContactManager.Common.Model;
02
using Joemwalton.ContactManager.Common.Repository;
03
 
04
namespace Joemwalton.ContactManager.Common.Services
05
{
06
    public class ContactsService : IContactsService
07
    {
08
        private IContactRepository _contactRepository;
09
        private INotificationService _notificationService;
10
 
11
        public ContactsService() { }
12
 
13
        //dependencies are now injected using the constructor
14
        public ContactsService(IContactRepository contactRepository,
15
                               INotificationService notificationService)
16
        {
17
            _contactRepository = contactRepository;
18
            _notificationService = notificationService;
19
        }
20
 
21
        public int SaveContact(Contact contact)
22
        {
23
            //code is simple and easy to understand!
24
            int id = _contactRepository.Save(contact);
25
            _notificationService.Send(contact);
26
            return id;
27
        }
28
 
29
        public IList<Contact> GetContacts()
30
        {
31
            return _contactRepository.FindAllContacts();
32
        }
33
 
34
        public Contact GetContact(int id)
35
        {
36
            return _contactRepository.FindById(id);
37
        }
38
 
39
        public void DeleteContact(int id)
40
        {
41
            _contactRepository.Remove(id);
42
        }
43
    }
44
}
45

First, add a new WCF Service to your project. You have an option to create a WCF service written in code or configuration. We will select the configuration option, which requires the addition of the ServiceModel configuration section. This will configure the endpoint including the address, binding and contract. The following is the web.config configuration section.

01
  <system.serviceModel>
02
      <services>
03
        <service name="ContactsService"
04
                 behaviorConfiguration="defaultBehavior">
05
          <host>
06
            <baseAddresses>
07
              <add baseAddress="http://localhost/ContactManager"/>
08
            </baseAddresses>            
09
          </host>
10
          <endpoint address=""
11
                    binding="basicHttpBinding"
12
                    contract="Joemwalton.ContactManager.Common.Services.IContactsService"/>
13
          <endpoint address="mex"
14
                    binding="mexHttpBinding"
15
                    contract="IMetadataExchange"/>
16
        </service>
17
      </services>  
18
      <behaviors>
19
            <serviceBehaviors>
20
                <behavior name="defaultBehavior">
21
                    <serviceMetadata httpGetEnabled="true" />
22
                    <serviceDebug includeExceptionDetailInFaults="true" />
23
                </behavior>
24
            </serviceBehaviors>
25
        </behaviors>
26
     <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
27
  </system.serviceModel>
28

The above ContactsService service configuration defines 2 endpoints. The first is the basicHttpBinding referencing our Joemwalton.ContactManager.Common.Services.IContactsService contract, which defines the service operations. This is not the concrete implementation, so this we will address in the next section. The basicHttpBinding is compatible with ASMX. The second is the MEX endpoint, which provides the meta-data information describing the service to consumers. The MEX endpoint is not exposed by default, so you can add this configuration. As you can see, we can add multiple service endpoints to provide the flexibility to communicate with a variety of consumers.

Since we selected a configuration-based WCF client, the svc file will be essentially empty (i.e. no code-behind for the service implementation). The following is the svc file, which you can edit the markup to include Spring.NET WCF configuration.

1
<%@ ServiceHost Language="C#" 
2
                Debug="true"
3
                Service="ContactsService"
4
                Factory="Spring.ServiceModel.Activation.ServiceHostFactory" %>

The 2 key attributes are Service and Factory. The Service attribute is the IoC object name of the concrete ContactsService implementation. The Factory attribute is set to the Spring.NET ServiceHostFactory, which provides the IoC Dependency Injection features. In this scenario, the factory will request an instance of the ContactsService object from the Spring.NET IoC container. You must set the Service attribute and IoC object name/id to the same value, which is necessary for the container to locate the correct object.

The next step is providing the instructions to the IoC container for wiring the objects, so the ServiceHostFactory returns the ContactsService object already initialized with all dependencies injected. In this case, the IContactRepository and INotificationService objects. The following is the XML meta-data defining the object for the IoC container.

01
<?xml version="1.0" encoding="utf-8" ?>
02
  <objects xmlns="http://www.springframework.net">
03
 
04
    <object id="EmailNotificationService"
05
            type="Joemwalton.ContactManager.Common.Services.EmailService, Joemwalton.ContactManager.Common">
06
      <constructor-arg name="smtpHost"  value="${Smtp.Host}" />
07
      <constructor-arg name="sender"    value="${Email.Sender}" />
08
      <constructor-arg name="subject"   value="Hello!" />
09
      <constructor-arg name="message"   value="Hello Email Contact!" />
10
    </object>
11
 
12
    <object id="ContactsService"
13
            type="Joemwalton.ContactManager.Common.Services.ContactsService, Joemwalton.ContactManager.Common"
14
            singleton="false">
15
      <constructor-arg name="contactRepository">
16
        <object type="Joemwalton.ContactManager.Common.Repository.SqlContactRepository, Joemwalton.ContactManager.Common" />
17
      </constructor-arg>
18
      <constructor-arg name="notificationService"
19
                       ref="EmailNotificationService" />
20
    </object>
21
  </objects>
22

The ServiceHostFactory will request the ContactsService object from IoC container by name/id. The container will instantiate the object based on the XML meta-data above, which references the type as ContactsService. The constructor is provided an instance of the SqlContactRepository and EmailNotificationService reference. The second constructor argument is a reference to another object, which is also defined in the XML meta-data as EmailNotificationService. If you are reading this post before the article describing the design patterns then I recommend reviewing the previous series for additional information.

Hosting

We basically built our WCF service and leveraged the Spring.NET IoC container to instantiate the service using WCF Service Host extensibility. Since we are exposing HTTP endpoint bindings, we will select IIS as the service host environment. The ContactManager.Soa.Server project, which will host our service under IIS. The web project will include the svc, XML meta-data and web.config. We will configure the web project to create a virtual directory and host under local IIS, so we can call the service locally for testing.

This configuration will allow us to access the service using the Project URL and service name. The following browser image represents the result when calling the service.

You can view the WSDL by clicking the link, which returns the following. As discussed previously, the WSDL provides the instructions for consumers to properly interact with your service.

Summary

In summary, we created a WCF service as a wrapper to an existing service. The POCO service is a concrete implementation containing the business logic to fulfill the request and respond appropriately. In our example, the service will call the Repository to persist data and a notification service to send email messages. We can still call the POCO service directly within the enterprise, but WCF offers a distributed architecture with options to communicate with external clients. Since we followed our core design patterns and principles, we introduced Spring.NET to provide an IoC container to instantiate and initialize our service. We are able to preserve all the design benefits of our non-distributed enterprise applications.

The following are a few additional items to consider.

  • The example is a standard synchronous request-response pattern with the client blocked, so consider an asynchronous request-response pattern for longer running service operations. One-way and duplex are also options.
  • Although HTTP is the most popular transport protocol, consider TCP and Named Pipes for a .NET only environment. The TCP and Named Pipes provide a performance boost over HTTP. 
  • IIS6 is a great hosting environment for HTTP based service endpoints, although Windows Process Activation Services (WAS)/II7 and a Managed Windows Service provide support for non-HTTP protocols.
  • Expose multiple endpoints to support legacy and non-.NET consumers (i.e. Java).
  • WCF provides many bindings including Web Services based on WS-I Basic Profile 1.1 (i.e. SOAP 1.1, WSDL 1.1) and the more advanced WS-* specifications.
  • Text encoding is standard, but binary and MTOM are options to reduce the payload and improve performance. You can define the encoding in the bindings. Check binding encoding restrictions.
  • Don’t forget about security for sensitive and confidential data!!! Transport and Message-based security are supported. The transport deals with protecting data over the wire, where SSL is the most common. Client Authentication is available with Windows credentials, certificates, SAML tokens and user/password secret.
  • Set the service XML meta-data object singleton attribute to false, so the IoC container creates a new instance.
  • Refer to the source code download for additional configuration and settings required for this solution not covered in the article.
Source Code

The source code for the solution contains several projects, which provide various scenarios and examples. The following is a brief summary of the projects.

  • ContactManager.Common – includes domain objects, repository and POCO services. The SqlContactRepository, LinqContactRepository and MemoryContactRepository are three Contact Repository concrete implementations. 
  • ContactManager.Soa.Server – includes the WCF service host with Spring.NET IoC support.
  • ContactManager.Soa.Client – includes the WCF service client.
  • ContactManager.Web – an MVC version of the Contact Manager UI with Spring.NET IoC support, which is currently setup to call the ContactManager.Common ContactsService POCO service. The ContactsService is currently configured to call the SqlContactRepository.
  • ContactManager.WinForm – a WinForm version of the Contact Manager UI, which is currently setup to call the ContactManager.Soa.Client. The ContactManager.Soa.Server is configured to call the LinqContactRepository using Spring.NET. 

You can download the source code and setup a local SQL Server database using the create scripts in the sql folder. You can also easily modify the Contact Repository implementation via the IoC container XML meta-data. The MemoryContactRepository is available for testing when you do not have a persistent data store available (e.g. SQL Server).

What’s Next?

I will follow-up with part 2 to discuss the service client setup and configuration, which does not require any external libraries or processes. The service host will handle the business and data tier, so the service client is a standard implementation.

I am also planning a Windows Workflow Foundation (WF) article as an alternative implementation for the business tier. In our example, the ContactsService method calls the Repository and NotificationService objects to fulfill the business requirement. We will replace this implementation with a workflow encapsulating this process and inject business rules into the workflow, which will also be exposed as a WCF service. If you have worked with Team Foundation Server (TFS) builds then you will be familiar with workflows.

I hope this article provides a WCF implementation, which follows the design patterns and principles for enterprise systems.

Source Code

Part VII: ASP.NET MVC Contact Manager with Spring.NET

2

This series is an adaption of my “Getting Started with Dependency Injection using Spring.NET” presentation, which was a session available at the Orlando .NET Code Camp 2012. Since I received invaluable participation and feedback from the attendees, this post will include expanded material and code examples.

This should be the final part of the series, which is the missing ASP.NET MVC example from the Orlando .NET Code Camp presentation. I received several requests to provide the ASP.NET MVC examples, since time expired before I was able to demonstrate during the presentation. I am including the Stick Contact Manager and Brick Contact Manager ASP.NET MVC versions, so you can download the source code. As discussed previously, the examples are primarily to provide the foundation for the design patterns and principles – not a full blown ASP.NET MVC web application with all the bells and whistles.

ASP.NET MVC is the perfect web architecture to promote our design patterns and principles we established throughout this series. The ASP.NET Web Forms paradigm is showing some age and not able to keep pace with evolving web technologies and increasing demands on applications. The Model-View-Controller design pattern is not page-centric like Web Forms, but instead is based on actions. The overall theme is separation, where the layers are maintainable, testable with a single responsibility. This sounds like everything we discussed, so let’s get started.

In Part IV, we refactored our prototype design and introduced the Stick Contact Manager. We applied several design patterns, which established a solid foundation for well-designed software. The design patterns and principles include Dependency Injection Principle (DIP), Separation of Concerns (SoC), Dependency Injection (DI) and Single Responsibility Principle (SRP). The Stick Contact Manager scored high marks during our evaluation, although we discovered one frustrating side-effect of the design – the client still must have knowledge of how to create the dependencies. We successfully eliminated the dependency creation throughout the majority of the objects, but we are forced to write significant code to create the dependencies.

The solution is centralizing the object creation or instantiation, so the client can delegate the task and knowledge of all the dependencies to another entity. This can also promote reusability, so the clients or consumers can also delegate this task to the same entity. This would eliminate the need for redundant client code required to create the dependencies.

So…let’s review the Stick Contact Manager MVC. Since we applied the Dependency Injection pattern, the dependencies are injected via the constructor. The core of MVC is the controller, which is responsible for processing the request and orchestrating the workflow to generate the appropriate response.

01
        private ContactsService _service;
02
        private ContactManager.Common.Repository.IContactRepository _repository;
03
        private ContactManager.Common.Services.INotificationService _notification;
04
 
05
        public ContactController() 
06
        {
07
            _repository = new ContactManager.Common.Repository.ContactRepository();
08
            _notification = new EmailService("myHost",
09
                                             "no-reply@test.com",
10
                                             "TEST", "Test Message");
11
            _service = new ContactsService(_repository,
12
                                           _notification,
13
                                           _notification);
14
        }
15

As discussed previously, the above Stick Contact Manager controller still must have knowledge of how to create the dependencies. As an alternative, we will introduce Inversion of Control (IoC) for our centralized object creation solution. An IoC container will handle the object creation, so now we can remove the majority of the instantiation code. In general, IoC inverts the relationship by the client delegating control to the container.

Let’s refactor the ContactController, so the Spring.NET IoC container will instantiate the object and inject all dependencies.

1
   public class ContactController : Controller
2
    {
3
        private ContactsService _service;
4
 
5
        public ContactController(ContactsService service)
6
        {
7
            _service = service;
8
        }

We significantly reduced the clutter regarding the instantiation of the objects, which has been delegated to the Spring.NET IoC container. How are we using Spring.NET IoC, because we do not see the code like the console application? This will require a small addition to the web.config, which allows the container to manage the instantiation and initialization of the participating objects. The following is the web.config entry to accomplish this task.

1
  <configSections>
2
    <sectionGroup name="spring">
3
      <section name="context" type="Spring.Context.Support.MvcContextHandler, Spring.Web.Mvc"/>
4
    </sectionGroup>
5
  </configSections>

How does the container know how to create the objects? Well, we will need to provide the instructions to the container. We will select the xml metadata configuration approach, so the object definition is contained in an external xml file. So…let’s look at the object definitions in the xml metadata files.

01
  <object type="MvcContactManager.Controllers.ContactController, MvcContactManager"
02
          singleton="false" >
03
    <constructor-arg ref="ContactsService"/>
04
  </object>
05
 
06
  <object id="ContactsService"
07
        type="ContactManager.Common.Services.ContactsService, ContactManager.Common">
08
    <!-- inline object -->
09
    <constructor-arg name="contactRepository">
10
      <object type="ContactManager.Common.Repository.ContactRepository, ContactManager.Common" />
11
    </constructor-arg>
12
    <constructor-arg name="helloNotificationService"    ref="HelloEmailNotificationService" />
13
    <constructor-arg name="goodbyeNotificationService"  ref="GoodbyeEmailNotificationService" />
14
  </object>
15
 
16
  <object id="HelloEmailNotificationService"
17
        type="ContactManager.Common.Services.EmailService, ContactManager.Common">
18
    <constructor-arg name="smtpHost"  value="${Smtp.Host}" />
19
    <constructor-arg name="sender"    value="${Email.Sender}" />
20
    <constructor-arg name="subject"   value="Hello!" />
21
    <constructor-arg name="message"   value="Hello Email Contact!" />
22
  </object>
23
 
24
  <!-- setter-based injection with abstract parent -->
25
  <object id="GoodbyeEmailNotificationService"
26
          type="ContactManager.Common.Services.EmailService, ContactManager.Common"
27
          parent="MailBase">
28
    <property name="Subject"  value="Hello!" />
29
    <property name="Message"  value="Hello Email Contact!" />
30
  </object>
31

We have 2 additional object definitions, so we can assign properties from external sources. In this case, we would like the web.config appSettings to be accessible to the objects. In the example above, the ${Smtp.Host} placeholder is replaced with the corresponding configuration appsettings value. The MailBase object contains the shared property values, which can be referenced using the parent attribute.

01
 <object type="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer, Spring.Core">
02
    <property name="VariableSources">
03
      <list>
04
        <object type="Spring.Objects.Factory.Config.ConfigSectionVariableSource, Spring.Core">
05
          <property name="SectionName" value="appSettings" />
06
        </object>
07
      </list>
08
    </property>
09
  </object>
10
 
11
  <object id="MailBase">
12
    <property name="SmtpHost" value="${Smtp.Host}" />
13
    <property name="Sender"   value="${Email.Sender}" />
14
  </object>

The element object contains the instructions to instantiate and initialize an object. The id or name attribute is the  reference name, which is the value that is passed when requesting an object from the IoC container. The type attribute is the namespace qualified class name and fully qualified assembly name. The primary object child elements include the constructor-arg and property, which provide constructor and setter based dependency injection techniques. There are several options to the constructor element, which include name and index attributes. The container will attempt to match the signature of the appropriate constructor, so providing the correct name or index of the parameters is important. The value attribute is the static value, expression or placeholder. In the example above, the ${Smtp.Host} value is replaced with the configuration appsettings value. The ref attribute identifies the name or id of another object element, so the value is set to this object.

Please refer to Part V or presentation for additional information regarding the xml metadata.

The remaining component of Spring MVC is the application routing, which requires some plumbing code to complete. The following is the Stick Contact Manager global.asax file with the traditional implementation required for registering the routes.

01
using System;
02
using System.Web;
03
using System.Web.Mvc;
04
using System.Web.Routing;
05
 
06
namespace MvcContactManager
07
{
08
    public class MvcApplication : System.Web.HttpApplication
09
    {
10
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
11
        {
12
            filters.Add(new HandleErrorAttribute());
13
        }
14
 
15
        public static void RegisterRoutes(RouteCollection routes)
16
        {
17
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
18
 
19
            routes.MapRoute(
20
                "Default", // Route name
21
                "{controller}/{action}/{id}", // URL with parameters
22
                new { controller = "Home",
23
                      action = "Index",
24
                      id = UrlParameter.Optional } // Parameter defaults
25
            );
26
        }
27
 
28
        protected void Application_Start()
29
        {
30
            AreaRegistration.RegisterAllAreas();
31
 
32
            RegisterGlobalFilters(GlobalFilters.Filters);
33
            RegisterRoutes(RouteTable.Routes);
34
        }
35
    }
36
}

This is a lot of redundant code and hard-coded route registration process, which could be cumbersome with more complex implementations. The Spring MVC approach is much simpler and requires no additional coding to define the application routing.

01
using System.Web;
02
using System.Web.Mvc;
03
using System.Web.Routing;
04
using Spring.Web.Mvc;
05
using Spring.Context.Support;
06
 
07
namespace MvcContactManager
08
{
09
    public class MvcApplication : SpringMvcApplication
10
    {
11
 
12
    }
13
}

The routing is mapped to the appropriate controller, where the action invoker matches the public method. The action method of the controller handles the HTTP POST, which will call the ContactsService to process the request. The console application follows the same process, which collects the input from the client and calls ContactsService. The following is the ContactController, which handles the Add action and like the console Contact Manager will delegate the responsibility to the ContactsService. The controller is not concerned with what is required to add a contact.

01
using System;
02
using System.Web;
03
using System.Web.Mvc;
04
using ContactManager.Common.Services;
05
using MvcContactManager.ViewModels;
06
using ContactManager.Common.Model;
07
 
08
namespace MvcContactManager.Controllers
09
{
10
    public class ContactController : Controller
11
    {
12
        private ContactsService _service;
13
 
14
        public ContactController(ContactsService service)
15
        {
16
            _service = service;
17
        }
18
 
19
        [HttpGet]
20
        public ActionResult Add()
21
        {
22
            var model = new ContactViewModel();
23
            return View(model);
24
        }
25
 
26
        [HttpPost]
27
        public ActionResult Add(ContactViewModel inputForm)
28
        {
29
            var model = new ContactViewModel(inputForm.Name,
30
                                             inputForm.Email,
31
                                             inputForm.Phone);
32
 
33
            //Check if model is valid and call service to add contact
34
            if (this.ModelState.IsValid)
35
            {
36
                _service.AddContact(new Contact(model.Name,
37
                                                model.Email,
38
                                                model.Phone));
39
            }
40
 
41
            return View(model);
42
        }
43
    }
44
}
45

The ContactViewModel is the model, which identifies the properties that will be available to the view. We also decorate the class with validation attributes, which will provide the input validation. We will also separate the view and domain models. The domain model will remain with the Contact Manager common library, where it represents the data managed by the data tier (i.e. database).

01
namespace MvcContactManager.ViewModels
02
{
03
    public class ContactViewModel 
04
    {
05
        public ContactViewModel()
06
            : this(string.Empty,
07
                  string.Empty,
08
                  string.Empty) { }
09
 
10
        public ContactViewModel(string name,
11
                                string email,
12
                                string phone)
13
        {
14
            this.Name = name;
15
            this.Email = email;
16
            this.Phone = phone;
17
        }
18
 
19
        [Required(ErrorMessage="Name is required.")]
20
        [StringLength(40, 
21
                      ErrorMessage="Name cannot be greater than 40.")]
22
        public string Name { get; set; }
23
 
24
        [Required(ErrorMessage = "Email is required.")]
25
        [RegularExpression(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$",
26
                           ErrorMessage = "Email not valid format.")]
27
        public string Email { get; set; }
28
 
29
        [Required(ErrorMessage = "Phone is required.")]
30
        [RegularExpression(@"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}",
31
                           ErrorMessage = "Phone not valid format (###)###-#### or (###)###-####.")]
32
        public string Phone { get; set; }
33
    }
34
}

The following is the view, which will present our form to add contact information. The controller populated the model, which is available for the view to present dynamic data. The ViewBag and ViewData are also collections available for the view. NOTE: the ViewBag is available under ASP.NET MVC3 and .NET 4.

01
@model MvcContactManager.ViewModels.ContactViewModel
02
@{ ViewBag.Title = "Add Contact"; }
03
 
04
@using (Html.BeginForm("Add", "Contact", FormMethod.Post))
05
{
06
<div id="AddEditor">
07
    @Html.ValidationSummary("Please correct errors below and click Add again:")
08
    <fieldset>        
09
        <legend>Contact</legend>
10
        <table cellpadding="0" cellspacing="0">
11
            <tr>
12
                <td><span style="text-align: right;">Name</span></td>
13
                <td>@Html.TextBox("Name", @Model.Name)@Html.ValidationMessage("Name", "*")</td>
14
            </tr>
15
            <tr>
16
                <td><span style="text-align: right;">Email</span></td>
17
                <td>@Html.TextBox("Email", @Model.Email)@Html.ValidationMessage("Email", "*")</td>
18
            </tr>
19
            <tr>
20
                <td><span style="text-align: right;">Phone</span></td>
21
                <td>@Html.TextBox("Phone", @Model.Phone)@Html.ValidationMessage("Phone", "*")</td>
22
            </tr>
23
        </table>    
24
        <p><input type="submit" value="Add"/></p>    
25
    </fieldset>    
26
</div>                      
27
}

The following is a screenshot of the rendered page, which is after our initial postback and validation.

Brick Contact Manager MVC

The IoC alternatives including Service Locator and Factory Design patterns also provide solutions for centralizing the object creation. The Factory Design hides the complexities with a factory object that contains static methods returning the instantiated object. The Service Locator is also a central repository, which the client passes a key to retrieve an object. These options also work well with the core Dependency Injection Principle (DIP), Separation of Concern (SoC), Dependency Injection (DI) and Single Responsibility Principle (SRP). I always recommend exploring your options and pick the approach that works best for your project.

In summary, the Brick Contact Manager MVC solves the object creation responsibility problem. I have found that following the software design principles we have defined in Part II and implementing the patterns in Part IV are a good defense against premature end-of-life scenario for your applications. The addition of an IoC container will further promote the software design principles and add significant value to your product. You will find maintenance and change requests will be less painful.

I hope you found this series helpful and will be able to follow the concepts presented with your next project. We completed .NET and Java examples to illustrate the design patterns and practices can be applied to any OO language. We also built a console application and MVC client, which provides guidelines for integrating with the Spring IoC container. Please follow the below links to source code and related posts for additional information.

Source Code

Part V: Brick Contact Manager – Console Application

Previous: Part IV: Stick Contact Manager

Java Version: Part VI: Brick Contact Manager

Go to Top