0

I'm editing a asp.net MVC project. There is javascript that makes an ajax call to an API controller. I didn't write this ajax script and it's been working fine. I've added some models (.cs files) to the data project and all of a sudden I get this error:

<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Could not create a 'IModelBinder' from 'DataSourceRequestModelBinder'. Please ensure it derives from 'IModelBinder' and has a public parameterless constructor.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace>
at     System.Web.Http.ModelBinding.ModelBinderAttribute.GetModelBinder(HttpConfiguration configuration, Type modelType) at System.Web.Http.ModelBinding.ModelBinderAttribute.GetBinding(HttpParameterDescriptor parameter) at System.Web.Http.ModelBinding.DefaultActionValueBinder.GetParameterBinding(HttpParameterDescriptor parameter) at System.Array.ConvertAll[TInput,TOutput](TInput[] array, Converter`2 converter) at System.Web.Http.ModelBinding.DefaultActionValueBinder.GetBinding(HttpActionDescriptor actionDescriptor) at System.Web.Http.Controllers.HttpActionDescriptor.get_ActionBinding() at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem..ctor(HttpControllerDescriptor controllerDescriptor) at System.Web.Http.Controllers.ApiControllerActionSelector.<>c__DisplayClass2.<GetInternalSelector>b__0(Object _) at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) at System.Web.Http.Controllers.ApiControllerActionSelector.GetInternalSelector(HttpControllerDescriptor controllerDescriptor) at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext) at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

I don't know what I've done to get this and can't find this error online. I've find questions about IModelBinder on StackOverflow and I seem to be doing everything write (for example, WebAPI ModelBinder Error).

What is causing this error and how do I fix this?

Here is the ajax call.

$.ajax({
        url: "/api/WorkOrderApi/GetNewAdminWorkOrder/" + vLocId + "?usr=" + vUsr + "&usrTyp=" + vUsrTyp,
        dataType: "json",
        type: "GET",
        success: function(model) {
            var viewModel = kendo.observable(model);

            kendo.bind(form, viewModel);
            var woAcct = $('#AcctId');
            woAcct.html(viewModel.AccountId);
         },
        error: function (XMLHttpRequest, textStatus, errorThrown)
        {
            alert("Status: " + textStatus); alert("Error: " + errorThrown);
        }

    });

Here is the server-side code in the controller. If I set a break point here, it does not get hit:

        public ARMS.OpenAccess.WrkOrdTemp GetNewAdminWorkOrder(int id, int usr, int usrTyp)
    {

        var obj = new ARMS.OpenAccess.WrkOrdTemp
        {
            ProblemDescription = ""
           ,
            WorkOrderStatus = 1
           ,
            WorkOrderDate = DateTime.Today
           ,
            WorkOrderPriority = 7
        };

        int compToUse = 0;

        string companyNameToUse = "";

        int locToUse = 0;

        string locationNameToUse = "";

        string acctIdToUse = "";

        var locObj = new List<ClsDataUtil>();

        obj.Companies = rep.GetCustomersByUsrIdandType(usr, usrTyp, out compToUse, out acctIdToUse, out locToUse, out locObj);

        if (id > 0)
        {
            compToUse = rep.GetCompanyIdByLocationId(id);
            acctIdToUse = rep.GetAccountIdByCompanyId(compToUse);
            locObj = (List<ClsDataUtil>)rep.GetCoLocationByCompanyId(compToUse);
            locToUse = id;
        }
        else if (id == 0)
        {
            compToUse = obj.Companies.FirstOrDefault().Id;
            acctIdToUse = rep.GetAccountIdByCompanyId(compToUse);
            locObj = (List<ClsDataUtil>)rep.GetCoLocationByCompanyId(compToUse);
            locToUse = locObj.FirstOrDefault().Id;
        }

        companyNameToUse = rep.GetCompanyNameById(compToUse);
        locationNameToUse = rep.GetLocationNameByLocationID(locToUse);
        obj.CompanyName = companyNameToUse;
        obj.LocationName = locationNameToUse;

        obj.Locations = locObj;

        obj.WoTempId = rep.UpdateWoTempCompandLoc(0, compToUse, locToUse);

        obj.ReferenceNumber = GetLocPo(locToUse);

        obj.CompanyId = compToUse;

        obj.AccountId = acctIdToUse;

        obj.LocationId = locToUse;

        obj.Vendors = (obj.LocationId == null || obj.LocationId == 0) ? rep.GetLocVendors() : rep.GetLocVendorsByPostal(obj.LocationId, obj.ServiceType);


        if (obj.Vendors.Count > 0)
            obj.VendorId = obj.Vendors.Select(x => x.Id).Min();

        obj.LaborWorkCodes = rep.GetCodeWorkByCodeTypeId(10).OrderBy(x => x.Name);

        obj.ServiceTypes = rep.GetWoServiceTypes();

        rep.UpdateWoTempServiceType(obj.WoTempId, obj.ServiceType);

        obj.PriorityTypes = rep.GetCodePriorityByForType("WorkOrder");

        var StatusTypes1 = rep.GetWorkCodeStatusActiveByType("WorkOrder").Where(x => !x.Name.ToLower().Contains("complete")).OrderByDescending(o => o.Name);
        var StatusTypes2 = rep.GetWorkCodeStatusActiveByType("WorkOrder").Where(x => x.Name.ToLower().Contains("to be approved"));
        IQueryable<ClsDataUtil> StatusTypes = StatusTypes1;
        ClsDataUtil statusType2 = StatusTypes2.FirstOrDefault();
        List<ClsDataUtil> lstStatusTypes = StatusTypes.ToList();
        lstStatusTypes.Add(statusType2);
        obj.StatusTypes = lstStatusTypes.AsQueryable();

        obj.RateTypes = rep.GetCodeTypesById(17);

        obj.Techs = rep.GetLocResourceTechsByVendor(obj.VendorId);

        obj.UseLocContract = "No";

        if (rep.HasLocContract(locToUse))
        {

            obj.LstCustomerContract = rep.GetRWOCoLocationContractByLocId(locToUse);

            obj.UseLocContract = "Yes";

        }
        else
        {
            obj.LstCustomerContract = rep.GetRWOCustomerContractByCompId(compToUse);
        }

        var venId = rep.GetCompanyIdByLocationId(obj.VendorId);

        obj.LstVendorContract = rep.GetVendorContracts(venId, compToUse);

        return obj;

    } // GetNewAdminWorkOrder

Here is the DataSourceRequestModelBinder.cs that derives from the IModelBinder class. I haven't made any changes to this since it was working.

using System;
using System.Collections.Generic;
using System.Web;
using System.Linq;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
using Kendo.Mvc;
using Kendo.Mvc.Infrastructure;
using Kendo.Mvc.UI;

namespace ARMS.ModelBinders
{
public class DataSourceRequestModelBinder : IModelBinder
{
    public DataSourceRequestModelBinder()
    {

    }
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        DataSourceRequest request = new DataSourceRequest();

        string sort, group, filter, aggregates;
        int currentPage;
        int pageSize;

        if (TryGetValue(bindingContext, GridUrlParameters.Sort, out sort))
        {
            request.Sorts = GridDescriptorSerializer.Deserialize<SortDescriptor>(sort);
        }

        if (TryGetValue(bindingContext, GridUrlParameters.Page, out currentPage))
        {
            request.Page = currentPage;
        }

        if (TryGetValue(bindingContext, GridUrlParameters.PageSize, out pageSize))
        {
            request.PageSize = pageSize;
        }

        if (TryGetValue(bindingContext, GridUrlParameters.Filter, out filter))
        {
            request.Filters = FilterDescriptorFactory.Create(filter);
        }

        if (TryGetValue(bindingContext, GridUrlParameters.Group, out group))
        {
            request.Groups = GridDescriptorSerializer.Deserialize<GroupDescriptor>(group);
        }

        if (TryGetValue(bindingContext, GridUrlParameters.Aggregates, out aggregates))
        {
            request.Aggregates = GridDescriptorSerializer.Deserialize<AggregateDescriptor>(aggregates);
        }

        bindingContext.Model = request;
        return true;
    }

    private bool TryGetValue<T>(ModelBindingContext bindingContext, string key, out T result)
    {
        var value = bindingContext.ValueProvider.GetValue(key);

        if (value == null)
        {
            result = default(T);

            return false;
        }

        result = (T)value.ConvertTo(typeof(T));

        return true;
    }
}

}

boilers222
  • 1,901
  • 7
  • 33
  • 71
  • `Please ensure it derives from 'IModelBinder' and has a public parameterless constructor.` - This error usually means that something is haywire with the DI configuration. Since you have a default constructor for that class, have a look at some classes that depend on it and how `IModelBinder` is setup to be resolved. – NightOwl888 Feb 15 '18 at 22:26
  • Thanks! What's DI? Any suggestions on what to look for (and where to look for) the setup? I don't ever have to touch those classes. – boilers222 Feb 16 '18 at 13:44
  • DI == Dependency Injection. Actually, after looking at your question again, it sounds like it is complaining that the **new models you added** don't have a default constructor. Could you show the code for them? – NightOwl888 Feb 16 '18 at 14:09
  • Thanks. There are too many to copy here (I using Telerik DataAccess and there's a model/class for each table), but I'm going through them. I don't see anything in the error message pointing out a specific model/class that's the problem. Is there any way to find out which model/class is causing the problem? – boilers222 Feb 16 '18 at 15:32

0 Answers0