简体   繁体   中英

MissingMethodException [Cannot create an instance of an interface] thrown selectively by ASP.NET MVC controller

I'm getting strange (at least for me) behavior in an MVC 4 application.

I'm googling around this whole evening; also I read many SO posts - no joy; I know I can't instantiate an interface directly.

In this particular application I'm using Ninject for DI. In the controller constructor I'm instantiating an interface and everything is peachy at that point - in fact I believe there is no problem with Ninject or its usage at all.

Also I'm sure this code was working once and no changes were introduced since then, except update of the Ninject library to 3.2.2.0 - can't remember which one was before that; obviously older one...

I have simple CRUD actions in that same controller which consumes another WEB service of mine. 2 out of 4 methods work correctly (LOL) - Index() and Create() . Update() and Delete() however are throwing the above mentioned exception; here it is the stack trace:

[MissingMethodException: Cannot create an instance of an interface.]
    System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
    System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +119
    System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +232
    System.Activator.CreateInstance(Type type, Boolean nonPublic) +83
    System.Activator.CreateInstance(Type type) +11
    System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) +183
    System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +563
    System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +416
    .
    .
    .

And here is the controller, very simple one, really...

public class NonFederalWorkingDayController : BaseController
{
    private readonly INonFederalWorkingDayManagementService _nonFederalWorkingDayService = null;

    public NonFederalWorkingDayController(INonFederalWorkingDayManagementService nonFederalWorkingDayService)
    {
        _nonFederalWorkingDayService = nonFederalWorkingDayService;
    }

    private JsonResultModel<IEnumerable<NonFederalWorkingDayDto>> InvokeService(Func<IEnumerable<NonFederalWorkingDayDto>, I9UserDto, IEnumerable<NonFederalWorkingDayDto>> operation, IEnumerable<NonFederalWorkingDayDto> models)
    {
        var result = new JsonResultModel<IEnumerable<NonFederalWorkingDayDto>>();

        if (ModelState.IsValid)
        {
            var modifier = new I9UserDto
            {
                Id = SiteContext.User.UserId
            };

            try
            {
                result.Model = operation(models, modifier);
                result.Message = "Operation completed successfully.";
            }
            catch (Exception ex)
            {
                result.HasError = true;
#if DEBUG
                result.Message = string.Concat("Operation failed: ", ex.Message);
#else
                result.Message = "Operation failed: Internal server error.";
#endif
            }

            if (result.Model != null)
            {
                foreach (var dto in result.Model)
                {
                    dto.CreatedOn = null;
                    dto.Creator = null;
                    dto.ModifiedOn = null;
                    dto.Modifier = null;
                }
            }
        }
        else
        {
            result.HasError = true;
            result.Message = "Invalid data.";
        }

        return result;
    }

    public ActionResult Index()
    {
        var model = _nonFederalWorkingDayService.Load();

        return View(model);
    }

    [HttpPost]
    public ActionResult Create(IEnumerable<NonFederalWorkingDayDto> models)
    {
        var result = InvokeService(_nonFederalWorkingDayService.Create, models);

        return Json(result);
    }

    [HttpPost]
    public ActionResult Update(IEnumerable<NonFederalWorkingDayDto> models)
    {
        var result = InvokeService(_nonFederalWorkingDayService.Update, models);

        return Json(result);
    }

    [HttpPost]
    public ActionResult Delete(IEnumerable<NonFederalWorkingDayDto> models)
    {
        var result = InvokeService(_nonFederalWorkingDayService.Delete, models);

        if (!result.HasError)
        {
            var plurality = models.Count() == 1 ? "Entity" : "Entities";
            result.Message = string.Concat(plurality, " deleted successfully.");
        }

        return Json(result);
    }
}

As I mentioned, the problem lies within the last two methods: Update() and Delete() . In fact, the execution never enters any one of them - the error gets raising during the model binding. But note how there is no interfaces except IEnumerable<> which binds just fine in other methods in the same application, including the Create() method in this very controller. I'm not sure how exactly, but the DefaultBinder seems smart enough to figure out that IEnumerable is actually a List . So this shouldn't be it, is it?

Also, I need to mention that I'm calling these actions through AJAX, not normal requests. Does that matters?

I seem to can't figure what is wrong ... please help!

UPDATE

I've inherit DefaultModelBinder in order to hook into the model binding pipeline. So I hooked into BindModel() and the controllerContext.Controller is actually fully functional instance of the NonFederalWorkingDayController

UPDATE 2

Here is the code listing for NonFederalWorkingDayDto :

public class NonFederalWorkingDayDto : DtoBase, INonFederalWorkingDay
{
    public static NonFederalWorkingDayDto Consume(INonFederalWorkingDay Donor)
    {
        NonFederalWorkingDayDto result = null;

        if (Donor != null)
        {
            result = DtoBase.Consume<NonFederalWorkingDayDto>(Donor);

            result.Description = Donor.Description;
            result.FallsOn = Donor.FallsOn;
            result.Id = Donor.Id;
            result.Name = Donor.Name;
        }

        return result;
    }

    public string Description { get; set; }

    public DateTime? FallsOn { get; set; }

    public string Name { get; set; }

    #region INonFederalWorkingDay support

    DateTime INonFederalWorkingDay.FallsOn
    {
        get { return FallsOn ?? default(DateTime); }
    }

    int IIdentifier<int>.Id
    {
        get { return Id ?? default(int); }
    }

    #endregion
}

I think your action declarations are the issue, try:

[HttpPost]
public ActionResult Create(List<NonFederalWorkingDayDto> models)
{
    ...
}

[HttpPost]
public ActionResult Update(List<NonFederalWorkingDayDto> models)
{
    ...
}

[HttpPost]
public ActionResult Delete(List<NonFederalWorkingDayDto> models)
{
    ...
}

Really the explanation is in the message ie it can't create an instance of the interface, as you've said the constructor is cool, so the problem lies with IEnumerable which needs to be a concrete enumerable class (like List for example).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM