The first module I regster stays as the required dictionary's model item type.

Topics: Customizing Orchard, General, Troubleshooting, Writing modules
May 29, 2013 at 11:09 PM
I am trying to convert several modules from a old site to run in orchard. They work fine when only one is enabled, but when one than one is enabled I receive this error trying to load the second module. "The model item passed into the dictionary is of type 'SecondActivatedModule', but this dictionary requires a model item of type 'FirstActivatedModule'."

I have found some resources on this error when people are creating widgets and they tend to modify the driver, but I will leave these applications as modules so I will not have a driver class.

Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
using A.B.Models;
using System.Transactions;
using Orchard.Themes;


namespace A.B.Controllers
{
    [Themed]
    public class ABController : Controller
    {

        
        public ActionResult Index()
        {
            // make a default model
            List<Models.ABRecord> model = new List<Models.ABRecord>();

            using (new TransactionScope(TransactionScopeOption.Suppress))
            {
                // go through our table to see what entries we have
                using (var db = new DatabaseModels.ABEntities())
                {
                    foreach (var record in db.AB_Registrant)
                    {
                        // add each one to our model
                        model.Add(new Models.ABRecord(record.Id));
                    }
                }
            }

            // return the view with the model
            return View(model);
        }

        /// <summary>
        /// Gets the data and returns it as a javascript object.
        /// </summary>
        /// <returns></returns>
        public string GetData()
        {
            List<Models.ABRecord> model = new List<Models.ABRecord>();

            using (new TransactionScope(TransactionScopeOption.Suppress))
            {
                using (var db = new DatabaseModels.ABEntities())
                {
                    foreach (var record in db.AB_Registrant)
                    {
                        model.Add(new Models.ABRecord(record.Id));
                    }
                }
            }

            System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            var data = serializer.Serialize(model);
            return data;
        }



        public ActionResult Details(int id)
        {
            // load the model
            var model = new ABRecord(id);

            // return the view with the model
            return View(model);
        }

        
 
        public ActionResult Edit(int id)
        {
            var model = new Models.ABRecord(id);
            return View(model);
        }



        [HttpPost]
        public ActionResult Edit(ABRecord model)
        {
            try
            {

                model.SaveToDatabase();
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }


 
        public ActionResult Delete(int id)
        {
            var model = new Models.ABRecord(id);
            return View(model);
        }



        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int id)
        {
            using (new TransactionScope(TransactionScopeOption.Suppress))
            {
                using (var db = new DatabaseModels.ABEntities())
                {
                    var registrant = db.AB_Registrant.Single(m => m.Id == id);
                    db.AB_Registrant.Remove(registrant);
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
            }
        }
    }
}
View
@{
    Style.Include("Admin.css").AtHead();
    Script.Include("jquery.dataTables.js").AtHead();
}
@model A.B.Models.ABRecord

@{
    ViewBag.Title = "Delete";
}


<fieldset class="detailsView">
    <legend>Registrant Information</legend>

    <div class="display-label">@Html.LabelFor(model => model.FirstName)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.FirstName)
    </div>

    <div class="display-label">@Html.LabelFor(model => model.LastName)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.LastName)
    </div>

    <div class="display-label">@Html.LabelFor(model => model.Email)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Email)
    </div>

    <div class="display-label">@Html.LabelFor(model => model.Specialization)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Specialization)
    </div>

    <div class="display-label">@Html.LabelFor(model => model.VegitarianMeal)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.VegitarianMeal)
    </div>

    <div class="display-label">@Html.LabelFor(model => model.Guests)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Guests)
    </div>

    <div class="display-label">@Html.LabelFor(model => model.GuestFirstName)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.GuestFirstName)
    </div>

    <div class="display-label">@Html.LabelFor(model => model.GuestLastName)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.GuestLastName)
    </div>

    <div class="display-label">@Html.LabelFor(model => model.GuestEmail)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.GuestEmail)
    </div>

    <div class="display-label">@Html.LabelFor(model => model.GuestVegitarianMeal)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.GuestVegitarianMeal)
    </div>
</fieldset>
@using (Html.BeginForm()) {
    <p>
        <input type="submit" value="Delete" /> |
        @Html.ActionLink("Back to List", "Index")
    </p>
}
Model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace A.B.Models
{
    public class ABRecord
    {
        #region Variables
        [Key]
        public int? ID { get; set; }
        [Display(Name = "First Name")]
        public string FirstName { get; set; }
        [Display(Name = "Last Name")]
        public string LastName { get; set; }
        public string Email { get; set; }
        public string Specialization { get; set; }
        [Display(Name = "Vegetarian Meal")]
        public bool? VegitarianMeal { get; set; }
        [Display(Name = "Vegan Meal")]
        public bool? VeganMeal { get; set; }
        #endregion


        #region Constructors
        /// <summary>
        /// Default Constructor.
        /// </summary>
        public ABRecord()
        {

        }

        /// <summary>
        /// Loads a record from the database.
        /// </summary>
        /// <param name="ID">ID of record to load.</param>
        public ABRecord(int ID)
        {
            try
            {
                LoadFromDatabase(ID);
            }
            catch (Exception e)
            {
                throw new Exception("Could not load record " + ID.ToString() + " from the database.", e);
            }
        }
        #endregion


        #region Database Methods
        /// <summary>
        /// Loads this object with a record from the database.
        /// </summary>
        /// <param name="ID">ID of the record to load.</param>
        public void LoadFromDatabase(int ID)
        {
            using (var db = new DatabaseModels.ABEntities())
            {
                var model = db.AB_Registrant.Where(reg => reg.Id == ID).SingleOrDefault();
                if (model == null)
                    return;

                this.ID = model.Id;
                this.Cancelled = model.Cancelled;
                this.ConfirmationSent = model.ConfirmationSent;
                this.Created = model.Created;
                this.Email = model.Email;
                this.FirstName = model.FirstName;
                this.GuestEmail = model.GuestEmail;
                this.GuestFirstName = model.GuestFirstName;
                this.GuestLastName = model.GuestLastName;
                this.Guests = model.Guests;
                this.GuestVeganMeal = model.GuestVeganMeal;
                this.GuestVegitarianMeal = model.GuestVegetarianMeal;
            }
        }

        /// <summary>
        /// Creates a new record or updates the current one.
        /// </summary>
        public void SaveToDatabase()
        {
            using (var db = new DatabaseModels.ABEntities())
            {
                var model = db.AB_Registrant.Where(reg => reg.Id == ID).SingleOrDefault();
                if (model == null)
                {
                    model = new DatabaseModels.AB_Registrant();
                    db.AB_Registrant.Add(model);
                }

                model.Cancelled = Cancelled;
                model.ConfirmationSent = ConfirmationSent;
                model.Created = Created;
                model.Email = Email;
                model.FirstName = FirstName;
                model.GuestEmail = GuestEmail;
                model.GuestFirstName = GuestFirstName;
                model.GuestLastName = GuestLastName;
                model.Guests = Guests;
                model.GuestVeganMeal = GuestVeganMeal;
                model.GuestVegetarianMeal = GuestVegitarianMeal;
                
                db.SaveChanges();
            }
        }
        #endregion
    }
}
My controller contains methods for 3 other views not listed, only the delete view is shown above. Also I am aware that my Model is missing some variables. For discretion I removed them. The first module and the second module have the same programming structure as above.

Any input is appreciated!
Developer
May 30, 2013 at 12:37 AM
Could you explain which exact action causes that error? Since you only pasted the Delete view, I'm assuming the error happens in the Delete action. If that's the case, then I don't see what could be causing that, as you seem to be passing the correct model type from the Delete action to the Delete view.
May 30, 2013 at 2:16 PM
From this example you are correct it would be coming from the delete action, but it is occurring on every action for every view.

I find it interesting that it always calls for the first module item type registered no matter if I register 1, or 3 modules after it. They all throw the error requiring item type module#1.

Am I setting something up wrong that Orchard is caching this value somewhere, or am I incorrect assuming I can leave these as modules when they really should be widgets?
Developer
May 30, 2013 at 5:18 PM
I think we should set the terminology straight first so we can better understand one another.
  • By module, do you actually mean model? Because you cannot call a module (nor a model for that matter. You call methods. Please be specific).
You are most definitely setting up something wrong, but I cannot see it based off these snippets, sorry.
May 30, 2013 at 6:11 PM
Sorry, in the previous comment I should have said enable module, not register.

To clear things up I have multiple mcv web applications that I have converted to Orchard modules based off of the code above. I was intending on running them as stand alone modules and not converting them to widgets. When I go into the Orchard dashboard and enable all of the modules the first one I enable will work, but every module after that produces the error "The model item passed into the dictionary is of type 'NthActivatedModule', but this dictionary requires a model item of type 'FirstActivatedModule'." So I am passing out the correct type, but for some unknown reason my view keeps requesting the model type of the first module i activated in the dashboard.

All of the modules work if I have only the current module being tested enabled and the rest of them disabled. This problems arises when more then one is enabled, and it occurs with every method call on every view. (ex. load a list of items on a index page, load a item and its values on a edit page)

Here is a example of the Routes.cs I am using as well
using Orchard.Mvc.Routes;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Routing;


namespace A.B
{
    public class Routes : IRouteProvider {
        public void GetRoutes(ICollection<RouteDescriptor> routes) {
            foreach (var routeDescriptor in GetRoutes())
                routes.Add(routeDescriptor);
        }

        public IEnumerable<RouteDescriptor> GetRoutes()
        {
            return new[] {
                new RouteDescriptor {
                    Priority = 5,
                    Route = new Route(
                        "applications/abadmin/{action}/{id}",
                        new RouteValueDictionary {
                            {"area", "A.B"},
                            {"controller", "B"},
                            {"action", "Index"},
                            {"id", UrlParameter.Optional}
                        },
                        new RouteValueDictionary(),
                        new RouteValueDictionary {
                            {"area", "A.B"}
                        },
                        new MvcRouteHandler())
                }
            };
        }
    }
}
The part that has me the most confused is that they all run fine standalone, but I get an error when I have more than one module enabled at a time.
Developer
May 30, 2013 at 7:35 PM
Aha. Perhaps something weird is going on when Orchard tries to locate the view to render, and if you have multiple views with the same name, it will pick the first one it finds. If that's the case, you should be able to reproduce by creating two new simple modules, both having a simple controller same actions, and returning like-named views. If you can reproduce, would you mind sending me that module so I can have a look?
May 31, 2013 at 5:42 PM
I created cat and dog modules, both with Index pages returning a list from a database. Same error persists when they are both enabled. What is the best way for me to give you the modules?
Developer
May 31, 2013 at 7:18 PM
Please zip and send to sipke at skywalkersd dot net.
Jun 10, 2013 at 9:37 PM
Has there been any progress made on this?
Coordinator
Jun 10, 2013 at 11:10 PM
Edited Jun 10, 2013 at 11:10 PM
Fixed a few seconds ago.

Named routes can be added multiple times in the case of a module
loaded in multiple tenants. There is no way to ensure a named route
is already registered, thus catching the specific exception.