Using the Model View Controller Pattern in C# ASP .NET

modified

Introduction

With the release of Visual Studio 2008, Microsoft is working on including an add-on for C# ASP .NET web application developers to include the Model view Controller (MVC) design pattern within their software architecture. While one of the add-on’s core purposes is to enhance URL functionality in a web application by enabling a model view controller pattern and design structure, the MVC design pattern itself, can be a powerful tool in your C# ASP .NET web applications.

What is the Model View Controller Design Pattern?

The Model View Controller (MVC) design pattern lets us pair loosley-coupled Models and Views together. In this manner, we can keep view logic completely separate from model logic. We can then interchange views or models with different classes, effectively changing an ASP .NET web application’s functionality with minimal side-effects.

Since this description may be confusing to developers who are new to the model view controller design pattern, let’s discuss in more detail what the individual parts of the MVC pattern entail.

What is a Model?

The Model in the MVC design pattern represents the core functionality of a class, such as the data processing. The Model has all functions required to process a piece of data, convert data, work with data, move data, etc. The Model performs processing on data behind the scenes and is generally a back-end logical process.

What is a View?

The View in the MVC design pattern represents the display functionality of the web application. The View controls how to display data, drawing controls, writing text, getting input from the user, outputting results, etc. Since a C# ASP .NET web application usually involves showing something to the user, retrieving input, processing the input, and displaying the results, you can see how the View directly interacts with the Model to perform the applications functionality.

What is a Controller?

The Controller can be considered the middle-man between the Model and View. Since the MVC design pattern lets us completely separate the Model from the View, an intermediary is needed in order for the two to communicate with each other. This is the job of the Controller. The Controller actually holds an interface of the Model and View, so that it can call the required functions of each.

The Controller takes a View and a Model in its contructor in order to setup the linking between the Model and View. The Controller’s flexibility is particularly important in that it allows us to pass it any combination of Model and View in the contructor. This actually allows us to link any type of Model with any type of View. If you think about this, this means we could create any variant of user interfaces and still use the same data processing logic (the Model). Or we could create any number of different ways to process a piece of data and still use the same user interface (the View).

Now that you have an idea of what each part on the model view controller design pattern entails, we can begin setting up the framework code to use this pattern.

Four Interfaces Seem Like a Lot

This design pattern actually begins with 2 interfaces to represent the Model and View. However, since the View needs to be able to talk to the Model and the Model needs to be able to talk to the View, we need 2 more adapter interfaces to allow them to communicate. In most scenerios, the View will communicate with the Model (and not the reverse), although we still allow the functionality for the other direction as well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface IModel
{
    void setAdapter(IModelAdapter a);
    object M(object input);
}

public interface IView
{
    void setAdapter(IViewAdapter a);
    void V();
}

public interface IModelAdapter
 {
    void V();
    // Any functions the model needs to call to be propogated to the view
}

public interface IViewAdapter
{
    object M(object input);
    // Any functions the view needs to call to be propogated to the model
}

In the above code, we start with an interface to define the Model and the View class. The view simply has one main function V(), which takes no parameters. We assume it displays a user interface for the user, possibly validates inputs entered by the user, and may even throw exceptions on invalid input. The Model has a main function M(), which takes an object as a parameter and returns an object. This allows us flexibility in the type of data we can pass to our model.

A Few Delegate Definitions

Next, we require two delegates to handle the connections for the Model and View factory methods. We simply define the two delegates as follows:

1
2
public delegate IModel ModelFactory();
public delegate IView ViewFactory();

Creating our First Concrete Model

Now that we’ve defined the interfaces, we can start on our concrete implementations of the MVC design pattern, starting with the Model. In this example, we’ll create a Model that simply encloses a string with dollar signs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Model : IModel
{
    private IModelAdapter _a;

    #region IModel Members

    public void setAdapter(IModelAdapter a)
    {
        _a = a;   
    }

    public object M(object input)
    {
        string name = (string)input;
        name = "$" + name + "$";

        return name;
    }

    #endregion
}

Notice in the above code we assign the adapter, which gives the Model a means to access the View, if neccessary. Our main logic is located in the M() function.

Creating our Concrete View

We can now create an implementation of the View (our user interface). In this example, our user interface will simply be the console screen. Our view will ask the user for their name, retrieve the input from the user, send the input to the Model for processing, and display the result.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class View : IView
{
    private IViewAdapter _a;

    #region IView Members

    public void setAdapter(IViewAdapter a)
    {
        _a = a;
    }

    public void V()
    {
        // Get some input from the user.
        Console.Write("What's your name? ");
        string input = Console.ReadLine();

        if (input.Length < 1)
        {
            Console.WriteLine("Please enter your name.");
            throw new Exception("ERROR - Name is empty.");
        }

        // Pass the input to the model to process.
        input = (string)_a.M(input);

        // Print the result.
        Console.WriteLine(input);
    }

    #endregion
}

Notice in the above code we setup the adapater, which gives the View access to the Model. In the main function V(), the view handles all user interface logic and then calls the Model to process data. With the Model and View defined, we only need one last part to link the magic together.

The Magical Controller

The Controller is the intermediary in the MVC design pattern and is required for setting up the actual linking between the concrete Model and View. The Controller keeps our linking loosley-coupled, so that we can easily replace any View with any other Model and vice-versa. Since the Controller handles both the Model and View, it will implement the interfaces of the adapters of both classes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Controller : IModelAdapter, IViewAdapter
{
    private IModel _model;
    private IView _view;

    public Controller(ModelFactory mf, ViewFactory vf)
    {
        _model = mf();
        _view = vf();

        _model.setAdapter(this);
        _view.setAdapter(this);
    }

    #region IModelAdapter Members

    public void V()
    {
        _view.V();
    }

    #endregion

    #region IViewAdapter Members

    public object M(object input)
    {
        return _model.M(input);
    }

    #endregion
}

The constructor of the Controller class takes the two delegates we defined earlier, which represent a conrete Model and View. The Controller then sets up the adapter (which happens to be itself, since the Controller is the intermediary). When the View needs to call the Model via the adapter, it ends up calling the Controller, which in turn fires off the Model’s appropriate method. If you consider the details behind the logic, the Controller is quite a powerful class.

Putting the MVC Design Pattern to Work

We can now utilize the model view controller design pattern in an example C# .NET application. We’ve defined a Model which encloses a name with dollar signs and we’ve defined a View which asks the user for their name via the console screen. We can now use the Controller to link them together. Note, we’ll need two factory methods to create an instance of the Model and View classes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
static void Main(string[] args)
{
    Controller c = null;

    // Dollar-sign the name.
    c = new Controller(MyDollarSignModelFactory, MyViewFactory);
    DoWork(c);

    Console.ReadKey();
}

public static void DoWork(Controller c)
{
    try
    {
        c.V();
    }
    catch (Exception excep)
    {
        DoWork(c);
    }
}

#region Factories

public static IModel MyDollarSignModelFactory()
{
    return new Model();
}

public static IView MyViewFactory()
{
    return new View();
}

#endregion

Output from running the example:

1
2
What's your name? John Doe
$John Doe$

The Real Power of the MVC Design Pattern

The basic example above shows that the model view controller pattern actually works. However, if all we needed was to enclose a name in dollar signs, we could perform this function in far less code. The real power of the MVC design pattern comes out when we need to create several different types of user interfaces or several different types of data processing. This is where code could become more complicated, but the MVC design pattern keeps it simple. To show this, let’s define another View. We’ll still use the console screen for our user interface, but suppose we wanted to change the language to Spanish? Instead of re-writing our View and replacing the English with Spanish, we can create a new concrete View as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class SpanishView : IView
{
    private IViewAdapter _a;

    #region IView Members

    public void setAdapter(IViewAdapter a)
    {
        _a = a;
    }

    public void V()
    {
        // Get some input from the user.
        Console.Write("¿Cuál es su nombre? ");
        string input = Console.ReadLine();

        if (input.Length < 1)
        {
            Console.WriteLine("Incorpore por favor su nombre.");
            throw new Exception("ERROR - el nombre es vacío.");
        }

        // Pass the input to the model to process.
        input = (string)_a.M(input);

        // Print the result.
        Console.WriteLine(input);           
    }

    #endregion
}

To use the new View, we simply link it in the model view controller in our main program as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static void Main(string[] args)
{
    Controller c = null;

    // Dollar-sign the name in spanish.
    c = new Controller(MyDollarSignModelFactory, MySpanishViewFactory);
    DoWork(c);

    Console.ReadKey();
}

public static IView MySpanishViewFactory()
{
    return new SpanishView();
}

Output from running the example:

1
2
¿Cuál es su nombre? John Doe
$John Doe$

Notice in our main program that all we had to do was replace MyViewFactory with MySpanishViewFactory. The Controller took care of linking together the new Spanish View with the same Model as before. We can do the same thing with a different Model. Likewise, you can link any combination of Model and View together.

Another Model

Let’s create another Model which doubles a name.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ModelDoubler : IModel
{
    private IModelAdapter _a;

    #region IModel Members

    public void setAdapter(IModelAdapter a)
    {
        _a = a;
    }

    public object M(object input)
    {
        string name = (string)input;

        name += name;

        return name;
    }

    #endregion
}

Now we can link together many combinations of the Views and Models as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
static void Main(string[] args)
{
    Controller c = null;

    // Dollar-sign the name in English.
    c = new Controller(MyDollarSignModelFactory, MyViewFactory);
    DoWork(c);

    // Double the name in English.
    c = new Controller(MyDoublerModelFactory, MyViewFactory);
    DoWork(c);

    // Dollar-sign the name in spanish.
    c = new Controller(MyDollarSignModelFactory, MySpanishViewFactory);
    DoWork(c);

    Console.ReadKey();
}

public static void DoWork(Controller c)
{
    try
    {
        c.V();
    }
    catch (Exception excep)
    {
        DoWork(c);
    }
}

#region Factories

public static IModel MyDollarSignModelFactory()
{
    return new Model();
}

public static IModel MyDoublerModelFactory()
{
    return new ModelDoubler();
}

public static IView MyViewFactory()
{
    return new View();
}

public static IView MySpanishViewFactory()
{
    return new SpanishView();
}

#endregion
}

You can see how the power behind the model view controller design pattern in a C# ASP .NET web application can provide us with a lot of functionality for loosley-coupled connections. Imagine changing the View user interface from console text to graphics or the web browser. Imagine changing the Model data processing from strings to XML or a database.

Conclusion

The Model View Controller design pattern in C# ASP .NET web applications allows us to link together user interface Views and data processing Models and a loosley-coupled fashion. We can achieve greater code re-use and separation of logical boundaries by implementing individual classes in this fashion.

While ASP .NET provides its own type of a View in the form of ASPX pages and its own type of a Model in the form .CS files, understanding the core functionality of the MVC design pattern can provide advantages in your software architecture and web application results.

About the Author

This article was written by Kory Becker, software developer and architect, skilled in a range of technologies, including web application development, machine learning, artificial intelligence, and data science.

Share