0

Being new to ASP MVC, I met the following problem.

I have a list of "repeating" controls on my page, which are presented by the following Razor code:

@model BankBLL.Interfaces.ISecureFolder

...(some irrelevant code here)

<header><h3 >Commitee list</h3></header>
@foreach (var commitee in Model.Commitees)
{
    <a href="@Url.Action("CommiteePage", "SecureFolder", commitee)">
        <div class="commiteeButtonImageContainer">@commitee.Name</div>
        <img src="~/Images/CommiteeButtonImage.png"/>
    </a>
}

Model.Commitees here is a List of ICommitee objects, that means that I am trying to "bind" each Url.Action to a corresponding ICommitee commitee object. However, when it comes to my controller action:

public ActionResult CommiteePage(ICommitee commitee)
{
    return View("CommiteePage", commitee);
}

looks like I am making it a wrong way, because application returns "Cannot create an instance of an interface." error, that means that application is unable to retreive required commitee object when the action link is clicked.

Is there a way to bind each row "item datacontext" (ICommitee object in this case) to correspoding Url.Action?

freeliner
  • 49
  • 3
  • 12

2 Answers2

1

Unfortunately could not post it earlier due to reputation regulations.

Finally resolved this issue due to good explanation at: HTML.ActionLink method

When you try to pass an argument from Url.Action or Html.ActionLink - you have to specify explicitly the final "null" argument responsible for html arguments.

In my case the following code works correctly:

slightly changed controller action (now receives just name instead of commitee object itself)

public ActionResult CommiteePage(string commiteeName)
{ 
    return View("CommiteePage", SecureFolder.Commitees.First(o=>o.Name == commiteeName));
}

and changed syntax for html calling this action:

@foreach (var commitee in Model.Commitees)
{
    <a href="@Url.Action("CommiteePage", "SecureFolder", new { commiteeName=commitee.Name }, null)">
        <div class="commiteeButtonImageContainer">@commitee.Name</div>
        <img src="~/Images/CommiteeButtonImage.png"/>
    </a>
}

Now view correctly passes the name of selected commitee to controller so that I can redirect to corresponding commitee view.

Thank you all for helping to resolve this issue!

Community
  • 1
  • 1
freeliner
  • 49
  • 3
  • 12
0

The main problem is that the default model binder cannot create an instance of an interface. Try to be more specific, i.e. public ActionResult CommiteePage(ImplementedCommiteeType commitee). You can also create a CommiteeViewModel: ICommitee class in which you can transport your structures (in Controllers and Views only).

Or you can create your own model binder which knows what to implement. This is slightly more complicated.

Gábor Imre
  • 5,899
  • 2
  • 35
  • 48
  • Thank you for your suggestion, I have tried to change ActionResult parameter to CommiteeModel class which is implementing ICommitee interface. However, the first problem was - "No parameterless constructor defined for this object" which I am sure means that serializer can't create an instance of this class, and after adding this parameterless constructor I found out that serializer cannot create instances of a CommiteeModel due to some properties of this class rely on constructor parameters to initialize correctly. – freeliner Jul 30 '13 at 13:33
  • @freeliner You have a few options. You can either define a default constructor on your CommiteeModel and allow the default model binder to construct everything for you, or you create a custom model binder that will tell it how to construct instances of either that or ICommitee. The latter is much more difficult. – Dismissile Jul 30 '13 at 13:43
  • Excuse me, missed your suggestion on using custom model binder. Will research it right now. – freeliner Jul 30 '13 at 13:46
  • Another different way is to send only the commitee Id. Then you can reload everything from DB on server-side. And you might use [Fiddler](http://fiddler2.com/get-fiddler) to check whether the data is going back to the server (see Elvin's comment). – Gábor Imre Jul 30 '13 at 15:48