ASP.NET MVC With WebApi and Attribute Routing

6 posts, 0 answers
  1. Joel
    Joel avatar
    7 posts
    Member since:
    May 2017

    Posted 28 Feb 2018 Link to this post

    I'm attempting to test out how the Telerik (Kendo) grid will work in a current application I have but am running into some roadblocks.

    I have a WebApi controller which inherits from ApiController and implements the following "Get" method:

    [System.Web.Http.HttpGet, System.Web.Http.Route(LookupUrl.MyLookup)] public DataSourceResult Get([System.Web.Http.ModelBinding.ModelBinder(typeof(WebApiDataSourceRequestModelBinder))]DataSourceRequest request)        

    {

                return service.GetModels().ToDataSourceResult(request);

    }

    and in the .cshtml file I have:

    @(Html.Kendo().Grid<MyModel>()           .Name("telerikGrid")           .Columns(col =>           {               col.Bound(c => c.Key);               col.Bound(c => c.DisplayName);               col.Bound(c => c.Inactive);           })           .Scrollable()           .Groupable()           .Sortable()           .Filterable()           .Pageable(pageable => pageable               .Refresh(true)               .PageSizes(true)               .ButtonCount(5))           .DataSource(d =>               d.WebApi()                   .Model(model =>                   {                       model.Id(p => p.Key);                   })                   .Events(events => events.Error("error_handler"))                   .Read(read => read.Url(Url.ApiUrl(LookupUrl.MyLookup)))           )     )

     

    The grid shows up correctly on the page, but the controller method is never accessed.  I'm not entirely sure what I am doing wrong here.

  2. Joel
    Joel avatar
    7 posts
    Member since:
    May 2017

    Posted 28 Feb 2018 in reply to Joel Link to this post

    Update to this. I have figured out my problem with the "Get" method not getting called and it is now getting hit properly. My problem now is that even though the "data" property of the return value has the correct number of records and the correct data in it, the results are not displayed on the screen.
  3. Joel
    Joel avatar
    7 posts
    Member since:
    May 2017

    Posted 28 Feb 2018 in reply to Joel Link to this post

    Update...again.  I added code to my .cshtml file to see where the response was going (other than into the abyss):

    @(Html.Kendo().Grid<Helion.Orcats.Models.Workflow.WorkflowUser>()       .HtmlAttributes(new Dictionary<string, object> { { "style", "width: 700px;" } })       

    .Name("WorkflowUsers")       

    .Columns(col =>       {           

         col.Bound(c => c.UserKey);           

         col.Bound(c => c.DisplayName);           

         col.Bound(c => c.Inactive);       })       

    .Scrollable()       

    .Groupable()       

    .Sortable()       

    .Filterable()       

    .Pageable(pageable => pageable           

         .Refresh(true)           

         .PageSizes(true)           

         .ButtonCount(5))       

    .DataSource(d =>           

         d.WebApi()               

           .Model(m => { m.Id(p => p.UserKey); })               

           .Read(read => read.Url(Url.ApiUrl(LookupUrl.WorkflowUsers_T)))               

           .Events(events =>               {                   

                   events.Error("error_handler");                   

                   events.Sync("sync_handler");                   

                   events.RequestEnd("request_end");               

    })  ))

     

    When the request ends, I use a console.log to see what is in the argument and he data is there.  How do I make sure that data gets set as the data source for the grid?

     

  4. Boyan Dimitrov
    Admin
    Boyan Dimitrov avatar
    2062 posts

    Posted 02 Mar 2018 Link to this post

    Hello,

    One of the main functionalities of the ToDataSourceResult extension method is to create a Data property in the response object. The DataSource expects this property to be named "Data" with capital D. If for some reason the data property (where items are stored in the response) is named with small letters the DataSource will not find the items. 

    Such situation can occur in ASP.NET Core. By default the json output is camelCase, but the "Data" is PascalCase. In our Getting Started article and specifically step 4 

    // Maintain property names during serialization. See:
    services
        .AddMvc()
        .AddJsonOptions(options =>
            options.SerializerSettings.ContractResolver = new DefaultContractResolver());
     
    // Add Kendo UI services to the services container

    the JSON serializer settings are changed to avoid this problem. 

    Regards,
    Boyan Dimitrov
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  5. Joel
    Joel avatar
    7 posts
    Member since:
    May 2017

    Posted 02 Mar 2018 in reply to Boyan Dimitrov Link to this post

    Boyan Dimitrov said:Hello,

    One of the main functionalities of the ToDataSourceResult extension method is to create a Data property in the response object. The DataSource expects this property to be named "Data" with capital D. If for some reason the data property (where items are stored in the response) is named with small letters the DataSource will not find the items. 

    Such situation can occur in ASP.NET Core. By default the json output is camelCase, but the "Data" is PascalCase. In our Getting Started article and specifically step 4 

    // Maintain property names during serialization. See:
    services
        .AddMvc()
        .AddJsonOptions(options =>
            options.SerializerSettings.ContractResolver = new DefaultContractResolver());
    // Add Kendo UI services to the services container

    the JSON serializer settings are changed to avoid this problem. 

    Regards,
    Boyan Dimitrov
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.

    While you are correct (I figured it out last night) that the problem was casing in the JSON data in the response, globally changing the case to Pascal Case would break the rest of the application.  I ended up intercepting the response and changing the contract resolver locally. I am trying to find a more ".NET" way of doing it, but until then the following code fixed it:

    [System.Web.Http.HttpGet, System.Web.Http.Route(LookupUrl.MyModels)]
            public HttpResponseMessage Get([System.Web.Http.ModelBinding.ModelBinder(typeof(WebApiDataSourceRequestModelBinder))]DataSourceRequest request)
            {
                return Request.CreateResponse(HttpStatusCode.OK, service.MyModels().ToDataSourceResult(request), GetFormatter());
            }
     
            private JsonMediaTypeFormatter GetFormatter()
            {
                var f = new JsonMediaTypeFormatter
                {
                    SerializerSettings = new JsonSerializerSettings {ContractResolver = new DefaultContractResolver()}
                };
     
                return f;
            }
  6. Joel
    Joel avatar
    7 posts
    Member since:
    May 2017

    Posted 02 Mar 2018 in reply to Joel Link to this post

    Oh and in case anyone is interested, this is not something I am doing in ASP.NET Core. This is an ASP.NET MVC app with WebApi.  To change the contract resolver globally (at least for WebApi), you need to go into the WebApiConfig.cs file and change it. If you want to change that file it looks like this:

    public static void Register(HttpConfiguration config)
            {
                config.MapHttpAttributeRoutes();
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
     
               config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver();
            }
Back to Top