Has no-one noticed the pathological coupling between a controller and a view? The concerns are separated nicely when a controller action creates view data and passes that to the view to render. Different views and view engines can be swapped in and out.
This is as it should be.
But what about the controller action that's invoked when a form is submitted? In all the examples I've seen, the controller action directly accesses the form variables from the request object. Surely this is a pathological coupling between controller and form,
requiring that the controller know the details of how the form rendered its input controls? What happens if a view is changed so that it gets its input in a different format? This would require changes to the controller action method.
What's the point of having all this clean separation when creating the form, but ignoring the monster under the stairs when the form is posted and the controller action has to deal with it?
Shouldn't the controller gather input in the same way as it supplies output to the view, i.e. in the form of view data, which may be generic and thus typed to a domain object? IOW, shouldn't a controller action request the view to return it the input data
in a domain object or property bag, just as the controller passes the output data to the form?
I don't think this is the greatest nastiness in the world. Looking at the contents of an HTTP request directly doesn't assume any actual knowledge about the nature of the form that was created. For example, something could just as easily be a text box as
a hidden field and the controller wouldn't know (or care). Passing data between Controller and View is an area where you can use a richer class such as ViewData. Remember however that at the start of a new page request, we are
not passing from a View to a Controller. We have started a new page request/response cycle. The only sort of data that can come in on a request are effectively key/value pairs, where all keys and values are strings (file uploads excepted).
Shouldn't the controller gather input in the same way as it supplies output to the view
Actually, you say that "The controls sends data to the view" and that is right. So why don't you say also "The view sends data to the controller" (which would be right) instead of your quoted statement?
The whole behavior seems correct to me. The controller is something that expects some data and outputs some other data, and the views work in the same way.
Example: The controller C1 expects data D1 and outputs D2. View V1 expects D2 and outputs D1. V1 submits its data to C1. All works fine.
You should change your view output only to match a new actionmethod or a modified one. The same way, you change your actionmethod output if you want to call a different view.
But the content of the HttpRequest is coupled to the exact rendering of the view. For example, say my model object has a property of type DateTime and I have a view that edits the model. The view receives the model and then has to render HTML to edit the
DateTime.
My first view form may render that as comboboxes, one for each of day, month, year and hours and minutes. So my controller action must know that in order to process the input, and combine the various values back into a DateTime.
Now consider that my customer doesn't like the comboboxes and I change the form to use an text box for the date part with a calender extension thrown in.
The problem is that the controller must also know this, and be changed accordingly so that it now parses a DateTime from the textual input from the input control.
This just seems completely inconsistent. In one direction I pass a nice model object to the view so that the controller has no pathological knowledge of the implementation of the view. But the controller then has to deal with artifacts generated by the particular
input controls generated by the view. This couples the controller directly to the particular implementation of the view. Not only that, but it's a pathological coupling, i.e. the controller must have knowledge of the internal implementation of the view, i.e.
the controls that it generates.
I propose that the view should have methods which parse the form input and return it in a high-level object, rather than in form values that are directly coupled to the particular way the view is implemented internally. In my example above, the view should
gather input from the controls it rendered to edit the DateTime and then convert that back into a DateTime. It should be the view's responsibility to do this, not the controller's.
I still can't follow you: every object does not know about his "caller" but MUST know about what it's calling. So the controller does know nothing about the view that called him, but must know about the view he's going to call. At the same way, the View
won't know nothing about the controller that called it, but must know about the controller it's going to post data to.
Shouldn't the controller gather input in the same way as it supplies output to the view
Actually, you say that "The controls sends data to the view" and that is right. So why don't you say also "The view sends data to the controller" (which would be right) instead of your quoted statement?
You're correct in that the view conceptually sends data to the controller. But the problem is in the form of that data and the knowledge that the controller must have of the view. The controller sends the view a high-level model object. It doesn't at that
point require any knowledge of how the view will decide to render it. Neither does it supply data to be edited in a form that's tied to the specific controls that the view will use to render it. Yet the controller
is tied to the controls used to render the model if it takes responsibility for rehydrating the model object from the form input. E.g. from my example above a DateTime value is supplied to the view, not separate Day, Month, Year, Hours and Minutes values.
The view may split the DateTime into exactly these components and render it into comboboxes. Then the controller has to deal with form input Day, Month, Year, Hours & Minutes instead of a single DateTime value that was passed in.
It's clearly the case that the view has the responsibility of rendering the model data into HTML input controls, so it should be the view which round-trips that back to the model when the form is submitted. That way, concerns are clearly separated. Changing
a view would have no impact on the controller
I still can't follow you: every object does not know about his "caller" but MUST know about what it's calling. So the controller does know nothing about the view that called him, but must know about the view he's going to call. At the same way, the View
won't know nothing about the controller that called it, but must know about the controller it's going to post data to.
But why must they know internals? The controller passes a model object to the view. The view renders that. It should be the view - which knows how it rendered it - that converts the form input back into a model object. It's a clear separation of concerns.
Otherwise, the controller has to have knowledge of the view layer and, even worse, the specifics of a particular view. Change that view and you have to change the controller. This is a violation of the SRP.
The solution, as I've said, is for the view to be responsible for transforming the model object into HTML fields
and back again. The controller can call a method on the view to do this. It's where the code goes which rehydrates the model that I have a problem with. That code should be in the view class. The contract between the controller and view should pass model
objects, not model objects one way and HTML form input the other way.
Looking at the contents of an HTTP request directly doesn't assume any actual knowledge about the nature of the form that was created.
Oh yes it does! :) Look at my example of editing a DateTime. The key/value pairs that the controller subsequently looks at depends on exactly how the view decided to render that date time for editing. So the controller is then coupled to a particular view
implementation. I'm saying that the view should be responsible for dealing with these key/value pairs, since it is responsible for the HTML controls which generated them.
Looking at it another way, how does the controller know what to do with these key/value pairs? It has to have explicit knowledge of the view. It's only because you as the developer wrote the view, or you guess it from looking at the key/value pairs and figure
out what they represent, or from looking at the view code to see what it does, or from looking at the HTML source. But the controller
shouldn't have to know! Only the view should have to know that. And it should be possible to change the view without changing the controller. This would be possible if the view took responsibility for dealing initially with the key/value pairs and transforming
them into something invariant, e.g. a model object.
I'm gonna go ahead and agree with ceilidhboy here. There is definitely a coupling between the form and your create action. The question is, can this be abstracted in a decent manner? I'm not so sure. I think this is the nature of http/html and part
of the beauty of the MVC framework is that it doesn't attempt to abstract the http/html model away from the developer.
...The question is, can this be abstracted in a decent manner?...
It depends on your defintion of decent ;-))
One way to do it is simply to have a method on the view which takes a NameValueCollection and returns a model object. ViewPage<T> could have a default virtual implementaion of this which returns default(T) or throws an unimplemented exception. A controller
could then require its views to override the method. This would remove the coupling and allow a controller to use any view which satisfied this contract.
ceilidhboy
Member
32 Points
18 Posts
Pathological coupling between Controller and View
Jul 29, 2008 01:34 PM|LINK
Has no-one noticed the pathological coupling between a controller and a view? The concerns are separated nicely when a controller action creates view data and passes that to the view to render. Different views and view engines can be swapped in and out. This is as it should be.
But what about the controller action that's invoked when a form is submitted? In all the examples I've seen, the controller action directly accesses the form variables from the request object. Surely this is a pathological coupling between controller and form, requiring that the controller know the details of how the form rendered its input controls? What happens if a view is changed so that it gets its input in a different format? This would require changes to the controller action method.
What's the point of having all this clean separation when creating the form, but ignoring the monster under the stairs when the form is posted and the controller action has to deal with it?
Shouldn't the controller gather input in the same way as it supplies output to the view, i.e. in the form of view data, which may be generic and thus typed to a domain object? IOW, shouldn't a controller action request the view to return it the input data in a domain object or property bag, just as the controller passes the output data to the form?
MikeS.
MelvynHarbou...
Star
8005 Points
1288 Posts
Re: Pathological coupling between Controller and View
Jul 29, 2008 01:55 PM|LINK
I don't think this is the greatest nastiness in the world. Looking at the contents of an HTTP request directly doesn't assume any actual knowledge about the nature of the form that was created. For example, something could just as easily be a text box as a hidden field and the controller wouldn't know (or care). Passing data between Controller and View is an area where you can use a richer class such as ViewData. Remember however that at the start of a new page request, we are not passing from a View to a Controller. We have started a new page request/response cycle. The only sort of data that can come in on a request are effectively key/value pairs, where all keys and values are strings (file uploads excepted).
Sgro
Participant
782 Points
352 Posts
Re: Pathological coupling between Controller and View
Jul 29, 2008 01:57 PM|LINK
Actually, you say that "The controls sends data to the view" and that is right. So why don't you say also "The view sends data to the controller" (which would be right) instead of your quoted statement?
The whole behavior seems correct to me. The controller is something that expects some data and outputs some other data, and the views work in the same way.
Example: The controller C1 expects data D1 and outputs D2. View V1 expects D2 and outputs D1. V1 submits its data to C1. All works fine.
You should change your view output only to match a new actionmethod or a modified one. The same way, you change your actionmethod output if you want to call a different view.
I see no flaws in the logic.
Web Developer
IWA Member
ceilidhboy
Member
32 Points
18 Posts
Re: Pathological coupling between Controller and View
Jul 29, 2008 02:18 PM|LINK
But the content of the HttpRequest is coupled to the exact rendering of the view. For example, say my model object has a property of type DateTime and I have a view that edits the model. The view receives the model and then has to render HTML to edit the DateTime.
My first view form may render that as comboboxes, one for each of day, month, year and hours and minutes. So my controller action must know that in order to process the input, and combine the various values back into a DateTime.
Now consider that my customer doesn't like the comboboxes and I change the form to use an text box for the date part with a calender extension thrown in.
The problem is that the controller must also know this, and be changed accordingly so that it now parses a DateTime from the textual input from the input control.
This just seems completely inconsistent. In one direction I pass a nice model object to the view so that the controller has no pathological knowledge of the implementation of the view. But the controller then has to deal with artifacts generated by the particular input controls generated by the view. This couples the controller directly to the particular implementation of the view. Not only that, but it's a pathological coupling, i.e. the controller must have knowledge of the internal implementation of the view, i.e. the controls that it generates.
I propose that the view should have methods which parse the form input and return it in a high-level object, rather than in form values that are directly coupled to the particular way the view is implemented internally. In my example above, the view should gather input from the controls it rendered to edit the DateTime and then convert that back into a DateTime. It should be the view's responsibility to do this, not the controller's.
Sgro
Participant
782 Points
352 Posts
Re: Pathological coupling between Controller and View
Jul 29, 2008 02:28 PM|LINK
I still can't follow you: every object does not know about his "caller" but MUST know about what it's calling. So the controller does know nothing about the view that called him, but must know about the view he's going to call. At the same way, the View won't know nothing about the controller that called it, but must know about the controller it's going to post data to.
Web Developer
IWA Member
ceilidhboy
Member
32 Points
18 Posts
Re: Pathological coupling between Controller and View
Jul 29, 2008 02:38 PM|LINK
You're correct in that the view conceptually sends data to the controller. But the problem is in the form of that data and the knowledge that the controller must have of the view. The controller sends the view a high-level model object. It doesn't at that point require any knowledge of how the view will decide to render it. Neither does it supply data to be edited in a form that's tied to the specific controls that the view will use to render it. Yet the controller is tied to the controls used to render the model if it takes responsibility for rehydrating the model object from the form input. E.g. from my example above a DateTime value is supplied to the view, not separate Day, Month, Year, Hours and Minutes values. The view may split the DateTime into exactly these components and render it into comboboxes. Then the controller has to deal with form input Day, Month, Year, Hours & Minutes instead of a single DateTime value that was passed in.
It's clearly the case that the view has the responsibility of rendering the model data into HTML input controls, so it should be the view which round-trips that back to the model when the form is submitted. That way, concerns are clearly separated. Changing a view would have no impact on the controller
ceilidhboy
Member
32 Points
18 Posts
Re: Pathological coupling between Controller and View
Jul 29, 2008 02:46 PM|LINK
But why must they know internals? The controller passes a model object to the view. The view renders that. It should be the view - which knows how it rendered it - that converts the form input back into a model object. It's a clear separation of concerns. Otherwise, the controller has to have knowledge of the view layer and, even worse, the specifics of a particular view. Change that view and you have to change the controller. This is a violation of the SRP.
The solution, as I've said, is for the view to be responsible for transforming the model object into HTML fields and back again. The controller can call a method on the view to do this. It's where the code goes which rehydrates the model that I have a problem with. That code should be in the view class. The contract between the controller and view should pass model objects, not model objects one way and HTML form input the other way.
ceilidhboy
Member
32 Points
18 Posts
Re: Pathological coupling between Controller and View
Jul 29, 2008 03:00 PM|LINK
Oh yes it does! :) Look at my example of editing a DateTime. The key/value pairs that the controller subsequently looks at depends on exactly how the view decided to render that date time for editing. So the controller is then coupled to a particular view implementation. I'm saying that the view should be responsible for dealing with these key/value pairs, since it is responsible for the HTML controls which generated them.
Looking at it another way, how does the controller know what to do with these key/value pairs? It has to have explicit knowledge of the view. It's only because you as the developer wrote the view, or you guess it from looking at the key/value pairs and figure out what they represent, or from looking at the view code to see what it does, or from looking at the HTML source. But the controller shouldn't have to know! Only the view should have to know that. And it should be possible to change the view without changing the controller. This would be possible if the view took responsibility for dealing initially with the key/value pairs and transforming them into something invariant, e.g. a model object.
malkir
Member
116 Points
42 Posts
Re: Pathological coupling between Controller and View
Jul 29, 2008 03:15 PM|LINK
I'm gonna go ahead and agree with ceilidhboy here. There is definitely a coupling between the form and your create action. The question is, can this be abstracted in a decent manner? I'm not so sure. I think this is the nature of http/html and part of the beauty of the MVC framework is that it doesn't attempt to abstract the http/html model away from the developer.
ceilidhboy
Member
32 Points
18 Posts
Re: Pathological coupling between Controller and View
Jul 29, 2008 03:41 PM|LINK
It depends on your defintion of decent ;-))
One way to do it is simply to have a method on the view which takes a NameValueCollection and returns a model object. ViewPage<T> could have a default virtual implementaion of this which returns default(T) or throws an unimplemented exception. A controller could then require its views to override the method. This would remove the coupling and allow a controller to use any view which satisfied this contract.