Problems understanding the MVC - please help

27 views
Skip to first unread message

Fritjolf

unread,
Jan 13, 2011, 1:18:53 AM1/13/11
to Community for ASP.NET MVC
Hi.

I'm building myself a test application.
A part of it is just a guestbook. This guestbook displays a subject
field, body field and below that the posts that has been inserted to
the guestbook. It's build on linq to sql.

The model for the page lookes like this:
public class ParentViewModel
{
public Message message { get; set; }
//List of messages. Remember that only PARENT messages must be
filled in here
public TimelineViewModel timeline { get; set; }
}

where message is a linq object and TimelineViewModel is just a
IEnumerable<Message> .
The idea behind this is that when I call the view the message object
will be attached to the subject and body field in my UI (using the
editfor html helper) and the timeline will contain the messages
already posted to the page and display them.

The view lookes like this:

The aspx page lookes like this:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/
Site.Master"
Inherits="System.Web.Mvc.ViewPage<VollaSkoleClient.Models.ParentViewModel>"
%>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent"
runat="server">
Member
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent"
runat="server">
<% using (Html.BeginForm("Member", "Parent")) %>
<% { %>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Hva ønsker du å si</legend>
<p>
<%= Html.LabelFor(l => l.message.HeaderText) %><br />
<%= Html.EditorFor(l => l.message.HeaderText)%>
<%= Html.ValidationMessageFor(l => l.message.HeaderText)%>
</p>
<p>
<%= Html.LabelFor(l => l.message.BodyText) %><br />
<%= Html.EditorFor(l => l.message.BodyText)%>
<%= Html.ValidationMessageFor(l => l.message.BodyText)%>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<% Html.RenderPartial("Timeline", Model.timeline); %>
</asp:Content>


The controller for the first call (meaning the Get function) lookes
like this:
[Authorize(Roles = "Parent")]
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Member()
{
using (VollaSkoleDataContext dc = new VollaSkoleDataContext())
{
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Message>(u => u.PortalUser);

dc.LoadOptions = options;

var model = new ParentViewModel
{
message = new Message(),
timeline = new TimelineViewModel { messages =
dc.GetParentMessages() }
};
return View(model);
}
}


And when I fill out some text in my subject and body and post back,
this triggers:
[Authorize(Roles = "Parent")]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Member(ParentViewModel model) //string header,
string body)
{
try
{
using (VollaSkoleDataContext dc = new VollaSkoleDataContext())
{
var message = new Message()
{
Category = "Parent",
UserId = dc.GetUserId(User.Identity.Name),
HeaderText = model.message.HeaderText,
BodyText = model.message.BodyText
};
if (ModelState.IsValid)
{
dc.Messages.InsertOnSubmit(message);
dc.SubmitChanges();
}
else
{
model.timeline = new TimelineViewModel { messages =
dc.GetParentMessages() };
return View(model);
}
}
}
catch
{
return View();
}
return RedirectToAction("Member", "Parent");
}


And it just doesn't work....
There are several problems. the model passed in is has the message
part of it with the new subject and body filled in, but the timeline
is null. Why? Secondly, I can't do a "ModelState.IsValid" at the top.
It always returns false. I suspect that is because the timeline object
is null and therefore the required fields in this object does not meet
the demands for my partial message class. (using data annotations on
this class). And if I try filling the timeline again (as shown above)
I get an exception when I come to the view with the error that the
datacontext is freed and cannot be accessed.

The thing I really can't seem to comprehend: for building a complexed
view I need a viewmodel. is it not correct that this view model should
contain both properties for updates (like message) and properties for
data to be displayed (like timeline) ???? If so, how do I post it back
to the controller? In my case I get the timeline which is null and
causes problems for me when I check ModelState.Isvalid - atleast I
suspect that to be the case...

I REALLY HOPE SOMEONE TAKES THE TIME TO READ AND TRY TO UNDERSTAND MY
PROBLEM AND HELP ME. I'M REALLY STUCK....

Please help me understand why it doesn't work...Or how to do this..

Thanx,
Fritjolf

Pete Mawhinney

unread,
Jan 18, 2011, 1:07:56 AM1/18/11
to c4...@googlegroups.com
Hi Fritjolf;

The first thing I notice is that your model.timeline is not part of the form and so it wont get posted back when the form gets submitted. You'd need to render the TimelineViewModel properties into the form as form elements so they get posted back and can be bound to the ParentViewModel parameter of the Member action in your controller. 

Hope this helps.

Cheers

-Pete 

--
You received this message because you are subscribed to the "Community for ASP.NET MVC" group.

To post to this group, send email to c4...@googlegroups.com

To unsubscribe from this group, send email to
c4mvc+un...@googlegroups.com
For more options, visit this group at
http://CommunityForMvc.Net

Rajendra Prasad

unread,
Jan 18, 2011, 5:14:02 AM1/18/11
to c4...@googlegroups.com
Hi  Fritjolf <Morten....@edb.com>,

this is rajendra Prasad

try this in your viewmodel make changes as follows

   public class ParentViewModel
   {
//declare a constructor  and
//in constructor
public ParentViewModel(Message message, TimelineViewModel timeline)
        {

            this.message = message;
            this.timeline = timeline;


        }

     public Message message { get; set; }
     
     public TimelineViewModel timeline { get; set; }
   }



///////

in u  r Controller the return type should be like this

return View(new ParentViewModel(message,timeline));


if it not works send the error message as it is.

hope this will ...

Fritjolf

unread,
Jan 19, 2011, 8:19:05 AM1/19/11
to Community for ASP.NET MVC
hi Pete, and thanx for your input.

What do you mean by model.timeline not being a part of the form and
therefore not part of the postback?

Inside my ParentViewModel (which is the input for the form) is both
message and the list of messages thats called timeline.

do you mean that I have to use the fields in the model to have them
posted back? Else they will not be posted back? Does that mean for
every field in the model? ie: lets say that the message has 10 other
properties not being used on this form, will they not be a part of the
postback?

thanx,
regards,
Fritjolf

On 18 Jan, 07:07, Pete Mawhinney <p...@pmic.com.au> wrote:
> Hi Fritjolf;
>
> The first thing I notice is that your model.timeline is not part of the form
> and so it wont get posted back when the form gets submitted. You'd need to
> render the TimelineViewModel properties into the form as form elements so
> they get posted back and can be bound to the ParentViewModel parameter of
> the Member action in your controller.
>
> Hope this helps.
>
> Cheers
>
> -Pete
>
> > c4mvc+un...@googlegroups.com <c4mvc%2Bunsu...@googlegroups.com>
> > For more options, visit this group at
> >http://CommunityForMvc.Net– Skjul sitert tekst –
>
> – Vis sitert tekst –

Tim Scott

unread,
Jan 19, 2011, 10:52:06 AM1/19/11
to c4...@googlegroups.com
Fritjolf,

That's correct. If it's not in the HTTP form post, it will not (cannot) be
bound to the controller action parameter.

To use MVC you will get the farthest by understanding how MVC interacts with
HTTP. The first thing to understand is that HTTP is stateless. That is,
once your app sends a response to the browser it has forgotten everything.
As far as it knows, no model ever existed and no response was ever sent.

When the user then submits the form, the browser sends an HTTP post request
to the server. MVC looks at this request and finds the right controller
action. Then it looks at the parameters to that action and uses parts of
the request (URL, query string, HTTP form) to instantiate those parameters.
If the parameter is a complex type, the binder will instantiate it and try
it's best to populate every writable public property. Typically it finds
what it needs in the HTTP form, which is a simple name-value collection of
strings. Properties that cannot be found in the form will be left with their
default values.

So yes, you have to take care of keeping state across request-response.
Putting all values that you care about in the form is one way to do it.
Values that the user does not need to see can be put into hidden element.
There are other ways, most of them bad.

The hardest part of learning MVC is unlearning WebForms. WebForms attempted
to make the web seems stateless while hiding HTTP from the developer. It
did this with viewstate and a complex "page lifecycle." This includes the
idea of "postback." The term postback implies that state is kept from
response to request, so I avoid using it in the context of MVC. I just say
"post" which is an HTTP verb that has nothing to do with ASP.

At first, handling state yourself can seem like an awful burden. But pretty
quickly you love getting closer to HTTP and shedding the abstractions of
WebForms, which many find to cause more headaches than it cures.

To deepen your understanding of this stuff, you might want to Google "MVC
model binding" and "MVC request lifecycle".

Tim Scott

>> ­ Vis sitert tekst ­


Fritjolf

unread,
Jan 19, 2011, 8:30:13 AM1/19/11
to Community for ASP.NET MVC
Hi rajendra and thank you for your reply.

If my controller would return this for the view:
return View(new ParentViewModel(message,timeline));
the timeline would be empty and would not be able to show any
messages.

Let me say: I'm new to mvc2, so parden me if I'm not getting what
you're trying to tell me...

but I do create a new object og ParentViewModel in the code:
var model = new ParentViewModel
{
message = new Message(),
timeline = new TimelineViewModel { messages =
dc.GetParentMessages() }
};
and I instanciate message and timeline as you see...

Wouldn't your suggested change only mean that the timeline would be
empty?

thanx,
regards,
Fritjolf


On 18 Jan, 11:14, Rajendra Prasad <rajaji....@gmail.com> wrote:
> Hi  Fritjolf <Morten.Jacob...@edb.com>,
> > c4mvc+un...@googlegroups.com <c4mvc%2Bunsu...@googlegroups.com>
> > For more options, visit this group at
> >http://CommunityForMvc.Net– Skjul sitert tekst –
>
> – Vis sitert tekst –

Fritjolf

unread,
Jan 20, 2011, 12:48:24 AM1/20/11
to Community for ASP.NET MVC
Hi Tim and thank you for helping.

I've been a windows programmer for 12 years and do not have much
experience with webforms. MVC2 is the first web technology I'd like to
learn - and learn well...


From your info above I gather that this is why you should have a
"NewMessageModel" with only the properties you would display in the
web page (or have bound to hidden fields), because these fields are
the only ones who will get posted back... ? But why can't I
instanciate properties in code like: <%
Model.ParentViewModel.message.Category = "Parent" %> .

I did solve the problem I initially had, but I fear it's not done in
"best practices" fashion....

This should be a common problem...
I have a web page displaying to fields for adding new messages and a
list containing the previous posted messages.
How would you model this viewModel and how would you take it back and
forth between the web page and the controller.. ?

Thanx a million for your help,

Fritjolf
> >> ­ Vis sitert tekst ­– Skjul sitert tekst –
>
> – Vis sitert tekst –
Reply all
Reply to author
Forward
0 new messages