Bannerman
Bannerman

Reputation: 101

Foreach statement using a nonaction method, does not contain a public method for 'GetEnumerator'

I have a controller "MessageController" with the following NonAction method:

    [ChildActionOnly]
    public IEnumerable<string> BackwardsListOfElements()
    {
        var allMessages = _messageRepository.GetAll().ToList();
        List<string> reversedMessages = new List<string>();
        for (int i = allMessages.Count-1; i --> 0; )
        {
            reversedMessages.Add(allMessages.ElementAt(i).Subject + ": " + allMessages.ElementAt(i).Body);
        }
        IEnumerable<string> returnEnumerable = reversedMessages;
        return returnEnumerable;
    }

It takes "messages" from the repository and reverses them and ignores the first message. In my view I would like to add the "returnEnumerable" messages from the above into a list. Below is the code for my view:

@model MyProject.UI.Models.MessageModel

@{
    var BackwardsListOfElements = @Html.Action("BackwardsListOfElements", "Message");
}

...

    <a class="btn btn-default dropdown-toggle" data-toggle="dropdown">
        <span class="caret"></span>
    </a>
    <ul class="dropdown-menu" role="menu">
        @foreach(var item in BackwardsListOfElements)
        {
            <li><a href="#">@Html.Label(item.Body)</a></li>
        }
    </ul>
</li>

BackwardsListOfElements is recognized as an MvcHtmlString. I have a compiler error that reads

Foreach statement cannot operate on variables of type 'System.Web.Mvc.MvcHtmlString' because 'System.Web.Mvc.MvcHtmlString' does not contain a public definition for 'GetEnumerator'.

Is it possible to iterate over BackwardsListOfElements without declaring my model as IEnumerable? Would this require writing my own foreach HTML helper? Is it possible to explicitly declare BackwardsListOfElements as System.Collections.IEnumerable?

Please let me know if you need more information. Thank you in advance for your help.

Upvotes: 1

Views: 648

Answers (2)

Bannerman
Bannerman

Reputation: 101

I ended up passing in my model as IEnumerable and looping through the items in the model as follows:

@using Myproject.UI.Helpers
@model IEnumerable<Myproject.UI.Models.MessageModel>

<li class="btn-group">
    <a href="@Url.Action("Index", "Message")" class="btn btn-default">
        <span class="badge">@Html.Action("NumberOfMessages", "Message")</span> @Html.Action("MostRecentMessage", "Message")
    </a>
    <a class="btn btn-default dropdown-toggle" data-toggle="dropdown">
        <span class="caret"></span>
    </a>
    <ul class="dropdown-menu" role="menu">
        @foreach (var item in Model)
        {
            <li>@Html.MenuItem(item.Subject+": "+item.Body, "Index", "Message")</li>
        }
    </ul>
</li>

I know I explicitly stated I did not want to pass in my model as IEnumerable, but there was no way around it. Thank you for your answers.

Upvotes: 0

Jenish Rabadiya
Jenish Rabadiya

Reputation: 6766

It wont work because @Html.Action("BackwardsListOfElements", "Message"); returns string not IEnumerable<string> as your childaction method returns.

You should pass IEnumerable in ViewData or in model and then you should iterate over them like below.

ViewData["someData"] = BackwardsListOfElements()

and use that in your view like following

var data = (IEnumerable<string>) ViewData["someData"]

foreach(var item in data)
{
     //your code here
}

or if you are having strongly typed model with Data property than you can go like following.

foreach(var item in Model.Data)
{
     //your code here
}

Upvotes: 1

Related Questions