Having trouble (IProxy error) passing a model into a ShapeResult I created in a Controller.

Topics: Troubleshooting, Writing modules
Aug 17, 2013 at 2:15 AM
Edited Aug 17, 2013 at 2:20 AM
I'm not sure if this is not possible because of dynamics, and even if it's possible I am not sure how to accomplish it. Admittedly, what I am trying to do is plop the code from a back-end Admin view from a working module into the front-end, but I don't think that's the problem.

I am trying to create a shape in a controller using ShapeResult. In my testing I was able to put some simple HTML in a .cshtml file and all was displayed properly.

However, now I am trying to take what I did in a regular page (see below) and put it into that shape. I am getting the "model item passed into the dictionary is of type 'IShapeProxy...', but this dictionary requires a model item of type 'MyNamespace.ViewModels.MyViewModel'." error.

I used a ShapeTemplateHarvester to get the shape from a subfolder I created in ~/Views (so it can find shapes in ~/Views/Main). With basic HTML, this is what I would do:

Controller:
public class MainController : Controller
{
    private readonly IOrchardServices _orchardServices;
    public MainController (IOrchardServices orchardServices)
    {
        _orchardServices = orchardServices;
    }
    public ActionResult Index()
    {
        return View();
    }
    //
    // Shapes
    public ShapeResult MyShape()
    {
        var shape = _orchardServices.New.Main_MyShape();
        return new ShapeResult(this, shape);
    }
}
This is the Index view in ~/Views/Main/Index.cshtml that worked with a plain HTML shape:
@model dynamic
@{ Layout.Title = T("Welcome to your Dashboard").ToString(); }
...
<div>
    @Display.Main_MyShape()
</div>
...
And this is the plain HTML shape in ~/Views/Main/MyShape.cshtml:
<p>SOME TEXT</p>
Again, this renders fine. The route for Index is fine.

Now I took some code/views I created in another module and was trying to re-jigger it into this type of flow. This is where I am sure I've made some type of mistake, but I cannot figure out how to solve it (if at all possible). My previous module worked well (I don't want to post the original code to avoid being repetitive, you can see what I originally did in what I am now trying to do) - it took inputs and saved them to the DB, and then I could see the inputs in ~/Admin with no problem. Although I created migrations/content parts and types, I ONLY created an empty driver. I am just trying to stress that everything I am trying to put into the shape works in an already existing module.

Here is what I am now trying to insert into the ShapeResult in the controller (previously in an Index ActionResult):
public ActionResult Index()
{
    return View();
}
public ShapeResult MyShape(PagerParameters pagerParameters)
{
    Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
    IContentQuery<MyPart, MyPartRecord> my = _myService.GetMy();
        var pagerShape = Shape.Pager(pager).TotalItemCount(my.Count());
        var myRequests = my
            .OrderByDescending<MyPartRecord>(cpr => cpr.MyCreatedUtc)
            .Slice(pager.GetStartIndex(), pager.PageSize)
            .ToList();
        var model = new MyViewModel
        {
            MyRequests = myRequests,
            Pager = pagerShape
         };
        var shape = _orchardServices.New.Main_MyShapet(model);
        return new ShapeResult(this, shape);
}
Things like myService are injected in the controller (again, it's working in the existing module).

Previously, in the working module, I did this in the ~/Views/Main/Index.cshtml (I stripped out the code that I am putting in ~/Views/Main/MyShape.cshtml, which I show immediately after):
@model MyViewModel
...
In my new ~/Views/Main/Index.cshtml I have this (mimicking what I did with the plaint HTML shape, except now I am trying to figure out how to pass the model):
@model dynamic
...
@Display.Main_MyShape()
Now, I am trying to do this in ~/Views/Main/MyShape.cshtml (this is what was in my original Index.cshtml in the working module):
@using MyNamespace.Models;
@using MyNamespace.ViewModels;
@using Orchard.Mvc.Html;
@using Orchard.Utility.Extensions;
@model MyViewViewModel
@{
    //Style.Require("Admin");
    Script.Require("ShapesBase");
}
<h1>@Html.TitleForPage(T("Review"))</h1>
<table class="items" summary="@T("This is a list of the requests.")">
    <thead>
        <tr>
            <th scope="col">&nbsp;&nbsp;</th>
            <th scope="col">@T("Request Date")</th>
            <th scope="col">@T("First Name")</th>
            <th scope="col">@T("E-Mail")</th>
            <th scope="col">@T("Question or Comment")</th>
            <th scope="col">Delete?</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var my in Model.MyRequests)
        {
        <tr>
            <td width="10%">@Html.ActionLink(T("Details").Text, "Details", new { controller = "Main", area = "MyNamespace", id = my.Id })</td>
            <td width="20%">@my.MyCreatedUtc.GetValueOrDefault()</td>
            <td width="15%">@my.FirstName</td>
            <td width="15%">@my.EMail</td>
            <td width="30%">@my.QuestionComment</td>
            <td width="10%">
                @{using (Html.BeginForm("Delete", "Main", new { area = "MyNamespace" }, FormMethod.Post, new { @class = "delete-form" }))
                  {
                      @Html.AntiForgeryTokenOrchard()
                      @Html.Hidden("id", my.Id)
                      @Html.Hidden("returnUrl", Context.Request.ToUrlString())
                      <input type="submit" value="Delete" />
                  }
                }
            </td>
        </tr>
        }
    </tbody>
</table>
@Display(Model.Pager)
And just for completeness, this is my view model:
public class MyViewModel
{
    public MyPartRecord MyPartRecord { get; set; }
    public List<Models.MyPart> MyRequests { get; set; }
    //Page lists in MyAdminController.cs
    public dynamic Pager { get; set; }
}
So, essentially, how can I pass the model into the shape? I tried this but got the same IProxy error I mentioned above (in the new Index.cshtml):
@model dynamic
@{
    var model = (MyNamespace.ViewModels.MyViewModel)Model;
}
...
@Display.Main_MyShape(model)
Thanks in advance for taking the time to read this.
Coordinator
Aug 17, 2013 at 6:36 AM
The shape is the model. If you want to pass in a strongly-typed model into the view, don't use a shape. It's as simple as that...