Base solution for your next web application
Open Closed

Abp adding additional Json fields to IActionResult and causing issues with Telerik Kendo UI binding Issues #8689


User avatar
0
mhdevelop created

Seems like two issues are caused when using abp controller as base

  1. When I just read json file and send content, additional fields are getting appended, how to override this functionality only for certail Action Methods?
public IActionResult ChangeOrder\_Read([DataSourceRequest] DataSourceRequest request)
{
    return Ok(System.IO.File.ReadAllText(@"Test.json"));
}
Contents of File:
{
"Data": [
    {
    "CatalogNumber": "Catalog 12345",
    "UsageCode": "Usage Code 1"
    },
    {
    "CatalogNumber": "Catalog 8234758",
    "UsageCode": "Usage Code 2"
    }
],
"Total": 0,
"AggregateResults": null,
"Errors": null
}
The data returned (abp added additional data, which causes kenddo grid not bind")
    {"result":"{\r\n  \"Data\": [\r\n    {\r\n      \"CatalogNumber\": \"Catalog 12345\",\r\n      \"UsageCode\": \"Usage Code 1\"\r\n    },\r\n    {\r\n      \"CatalogNumber\": \"Catalog 8234758\",\r\n                  \"UsageCode\": \"Usage Code 2\"\r\n\r\n    }\r\n\r\n  ],\r\n  \"Total\": 0,\r\n  \"AggregateResults\": null,\r\n  \"Errors\": null\r\n}","targetUrl":null,"success":true,"error":null,"unAuthorizedRequest":false,"__abp":true}
    

16 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team

    hi

    The WrapResult and DontWrapResult attributes can be used for methods and classes to enable/disable wrapping.

    https://aspnetboilerplate.com/Pages/Documents/Javascript-API/AJAX?#wrapresult-and-dontwrapresult-attributes

  • User Avatar
    0
    mhdevelop created

    That helped with result formating. Still the grid is not binding. I can make same work without abpnetzero in standard asp.net core mvc 3.1 project. Once I use asp.net zero, the grid binding stops working.

    Do you have a sample to show how to make it work?

    If this does not work, I might end up scrapping asp.net zero enterprize license. I just bought couple days ago. Any help sample greatly appreciated.

    Let me know if you need sample project. you should be able to use 30day trial of asp.net core mvc jquery telerik ui. I think this is not just my problem, but any enterprise users using asp.net zero.

    Thanks

  • User Avatar
    0
    BobIngham created

    @mhdevelop - create a controller for your grid in the Web.Host project: Here's a simple example of a method:

            [DontWrapResult(WrapOnError = true)]
            public async Task<JsonResult> GetActionsForEdit([DataSourceRequest]DataSourceRequest request, int isDeleted, long? parentId)
            {
                //for testing...
                isDeleted = 0;
                try
                {
                    var query = await _ncActionService.GetNcActionsForEdit(isDeleted, parentId).ConfigureAwait(false);
                    var model = await query.ToDataSourceResultAsync(request).ConfigureAwait(false);
                    return Json(model);
                }
                catch (Exception ex)
                {
                    throw new Exception(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.ToString(), ex);
                }
            }
    

    Don't give up, Zero plays really nicely with Kendo Angular. In your Angular project create a separate service for Kendo grids: That code looks like this:

    import { Injectable, Inject, Optional, InjectionToken } from '@angular/core';
    import { HttpClient, HttpParams } from '@angular/common/http';
    import { toDataSourceRequestString, translateDataSourceResultGroups, translateAggregateResults, DataResult, DataSourceRequestState } from '@progress/kendo-data-query';
    import { GridDataResult } from '@progress/kendo-angular-grid';
    import { Observable } from 'rxjs';
    import { map } from 'rxjs/operators';
    
    import { API_BASE_URL } from '@shared/service-proxies/service-proxies';
    import * as moment from 'moment';
    
    @Injectable({
      providedIn: 'root'
    })
    export class KendoGridService {
      private http: HttpClient;
      private baseUrl: string;
    
      constructor(
        @Inject(HttpClient) http: HttpClient,
        @Optional() @Inject(API_BASE_URL) baseUrl?: string) {
        this.http = http;
        this.baseUrl = baseUrl ? baseUrl : '';
      }
    
      getActions(
        state: DataSourceRequestState,
        isDeleted): Observable<DataResult> {
        let params = new HttpParams();
        params = params.append('isDeleted', isDeleted);
    
        let url_ = this.baseUrl + '/kendogrid/GetActions';
        url_ = url_.replace(/[?&]$/, '');
        const queryStr = `${toDataSourceRequestString(state)}`; // Serialize the state
        const hasGroups = state.group && state.group.length;
    
        return this.http
          .get(`${url_}?${queryStr}`, { params: params })
          .pipe(map(({ data, total /*, aggregateResults*/ }: GridDataResult) => // Process the response
            (<GridDataResult>{
              // If there are groups, convert them to a compatible format
              data: hasGroups ? translateDataSourceResultGroups(data) : data,
              total: total,
              // Convert the aggregates if such exist
              //aggregateResult: translateAggregateResults(aggregateResults)
            })));
      }
    

    Call your service from your component, casting your dates back to javascript dates:

      getDevicesForKendo() {
        this.gridLoading = true;
        this._kendoGridService.getDevices(this.deviceGridSettings.state,
          this.userId,
        )
          .subscribe((data) => {
            data.data.forEach((d) => {
              d.creationTime = new Date(d.creationTime);
              d.deletionTime = new Date(d.deletionTime);
              d.lastModificationTime = new Date(d.lastModificationTime);
            });
            this.deviceGridSettings.gridData = data;
            this.gridLoading = false;
          }, (error: HttpErrorResponse) => {
            this.gridLoading = false;
            if (error.status === 401) {
              //this to capture refresh of grid when login has expired
              abp.message.confirm(null, this.l('LoginHasExpired'), function (isConfirmed) {
                if (isConfirmed) {
                  abp.auth.clearToken();
                  abp.utils.setCookieValue(AppConsts.authorization.encrptedAuthTokenName, undefined, undefined, abp.appPath);
                  location.href = '';
                }
              });
            } else {
              abp.message.error(this.l('KendoGridError', this.l('NcDevice')), this.l('Error'));
            }
          });
      }
    

    Hope that helps.

  • User Avatar
    0
    mhdevelop created

    Thanks for the quick response. Grearly appreciated. We are not using angular: We are using asp.net core mvc 3.1 with telerik kendo ui for jQuery. Any sample with that combination will help.

  • User Avatar
    0
    mhdevelop created

    This one issue is holding up all project.

    Thanks V

  • User Avatar
    0
    BobIngham created

    I can't help you there, I'm afraid. But I do have a colleague who uses the MVC version. I will email him the forum link and maybe he can help you.

  • User Avatar
    0
    mhdevelop created

    Thank you Bob. The funny part is Telerik grid is working with aspbboilerplate 5.2 but not with paid aspmetzero version. No response yet from volvosoft yet.

    Here is some more details on the problem https://stackoverflow.com/questions/60738147/kendo-grid-not-binding-to-data-in-asp-net-mvc-core

  • User Avatar
    0
    BobIngham created

    It's past midnight here but I sent an email, I'm sure my colleague will be in touch first thing as long he's not in meetings, which is doubtful given current lockdown conditions! Can't do any more for you right now I'm afraid. I suggest you post your "onDataBinding()" and "onDataBound()" methods - there may be something in there. Anything in the browser console at all?

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @mhdevelop

    AspNet Boilerplate and AspNet Zero behaves similar actually. Could you share your project with [email protected] for us to check your problem ?

    Thanks,

  • User Avatar
    0
    mhdevelop created

    Helopp @ismcagdas,

    I have shared the link to zipped folder with [email protected]. Thanks for alll your engagement and support.

    Thanks

  • User Avatar
    0
    mhdevelop created

    also, if you can give me github login name I can share the github repo of the project too

  • User Avatar
    0
    mhdevelop created

    you are now added to my git repo. I have created a page under plcm\home called grid and added controller method and data read ajax call to home controller. Major change I have done is as explained in Telerik getting started instructions.

    in Layout page I moved all aspnetzero java script to header and added kendo javascript libraries. you can see kendo date control working on home page. Also going to \plcm\home\products_read you can data is returned properly but not bound correctly.

    Thanks V

  • User Avatar
    0
    mhdevelop created

    If you are going to pull from repo i tried couple more things. Created new controler KendoController and Created few views with own layout to see if it helps. There are two views one ClientBound and other ServerBound. The ClientBound still does not work. Not sure something in startup in interfearing with databinding for kendo grid.

    Thanks v

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    It seems like Kendo Grid requires all property names in Json response to be uppercase. We may change Json serialization approach of ASP.NET Core, but it might break other parts of the app. So, I implemented a workaround like this;

    public class MyDataSourceResult : DataSourceResult
        {
            [JsonProperty("Data")]
            public new IEnumerable Data { get; set; }
    
            [JsonProperty("Total")]
            public new int Total { get; set; }
    
            [JsonProperty("AggregateResults")]
            public new IEnumerable<AggregateResult> AggregateResults { get; set; }
    
            [JsonProperty("Errors")]
            public new object Errors { get; set; }
        }
    
        public class ProductDto
        {
            [JsonProperty("ProductName")]
            public string ProductName { get; set; }
    
            [JsonProperty("UnitPrice")]
            public string UnitPrice { get; set; }
    
            public  List<ProductDto> GetList()
            {
                var products = new List<ProductDto>();
                products.Add(new ProductDto { ProductName = "Product 1", UnitPrice = "2.0" });
                products.Add(new ProductDto { ProductName = "Product 2", UnitPrice = "3.0" });
                products.Add(new ProductDto { ProductName = "Product 4", UnitPrice = "4.0" });
                products.Add(new ProductDto { ProductName = "Product 5", UnitPrice = "2.0" });
                products.Add(new ProductDto { ProductName = "Product 6", UnitPrice = "9.0" });
                products.Add(new ProductDto { ProductName = "Product 7", UnitPrice = "2.0" });
                return (products);
            }
        }
    

    and, modified controller action like this;

    [DontWrapResult]
            public JsonResult Products_Read([DataSourceRequest]DataSourceRequest request)
            {
                return Json(new MyDataSourceResult
                {
                    Data = new ProductDto().GetList(),
                    Total = 6
                });
            }
    

    If this works, you can remove me from your Github repo.

    Thanks,

  • User Avatar
    0
    mhdevelop created

    Thank you, that work around works. I am not sure what new challenges it brings. Also I noticed if I remove services.NetwonsoftJason() the telerik will work, but Abp will stop working.

    Thank you very much for quick response. I will remove you from Github repo.

    Thanks V

  • User Avatar
    0
    BobIngham created

    @mhdevelop: In your grid controller implement a new contract resolver to overwrite the standard Zero contract resolver. e.g.

    var accounts = await _contactManagerAppService.GetAccounts();
    var contractResolver = new JsonSerializerSettings {ContractResolver = new DefaultContractResolver()};
    return Json(await accounts.Items.ToDataSourceResultAsync(request), contractResolver);
    

    That should save you from having to override the DataSource object. I know this forum post is closed but hopefully you should get a copy in email.