How to Integrate the Telerik UI for ASP.NET Core (Kendo) components with the ABP MVC UI?
Introduction
Hi, in this step by step article, we will see how we can integrate the Telerik UI for ASP.NET Core (Kendo) components with our Abp MVC app.
Creating the Solution
ABP Framework offers startup templates to get into business faster.
In this article, I will create a new startup template with EF Core as a database provider and MVC for UI framework. But if you already have a project with MVC UI, you don't need to create a new startup template, you can directly implement the following steps to your existing project.
If you already have a project with the MVC UI, you can skip this section.
- Before starting to development, we will create a solution named
TelerikComponents
(or whatever you want). We will create a new startup template with EF Core as a database provider and MVC for UI framework by using ABP CLI:
abp new TelerikComponents --ui mvc --database-provider ef
- Our project boilerplate will be ready after the download is finished. Then, we can open the solution in the Visual Studio (or any other IDE) and run the
TelerikComponents.DbMigrator
to create the database and seed initial data (which creates the admin user, admin role, permissions, etc.). I prefer changing the db connection string in the DbMigrator project to(localdb)\\mssqllocaldb
to be able to just run right away.
"ConnectionStrings": {
"Default": "Server=(localdb)\\mssqllocaldb;Database=TelerikComponents;Trusted_Connection=True"
},
- After the database and initial data created,
- Run the
TelerikComponents.Web
project to see our UI working.
Default login credentials for admin: username is admin and password is 1q2w3E*
Implementation
Pre-requisite
First thing we need to do is downloading the Progress Control Panel to get Telerik Kendo components on our development machine.
If you are using Telerik UI for ASP.NET Core components for the first time or you don't have an active license you can click here to download free trial.
You can find the more installation details from here.
Step 1 (Configuration)
- We need to install the
Telerik.UI.for.AspNet.Core
NuGet package to our web project (*.Web
). We need to choose the Telerik feed package source to see the package. - If you're using the trial, install
Telerik.UI.for.AspNet.Core.Trial
package via NuGet.
- In package.json, add the kendo script component as a dependency. This will get the scripts in your
node_modules
directory. A note, the npm package from Telerik needs to be transpiled to be able to be used so we're basically following their npm+webpack documentation here with a few adjustments for abp.io setup:
{
{
"version": "1.0.0",
"name": "my-app",
"private": true,
"main": "main.js",
"devDependencies": {
"webpack": "^5.26.3",
"webpack-cli": "^4.5.0"
},
"dependencies": {
"@volo/abp.aspnetcore.mvc.ui.theme.lepton": "^4.2.2",
"@volo/account": "^4.2.2",
"@volo/audit-logging": "^4.2.2",
"@volo/identity": "^4.2.2",
"@volo/saas": "^4.2.2",
"@progress/kendo-theme-bootstrap": "4.33.0",
"@progress/kendo-ui": "2021.1.225",
"css-loader": "^5.1.3",
"expose-loader": "^2.0.0",
"style-loader": "^2.0.0"
},
"scripts": {
"build": "webpack"
}
}
}
Create a main.js
in the root directory, this is what webpack will use to know what to include in the transpiled js bundle.
import $ from 'jquery';
window.jQuery = $; window.$ = $;
import "@progress/kendo-ui";
import "@progress/kendo-ui/js/kendo.aspnetmvc";
import "@progress/kendo-ui/js/kendo.timezones";
import "@progress/kendo-theme-bootstrap/dist/all.css";
Finally, add a webpack.config.js
file to the root directory of your web project with the following content:
"use strict"
{
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './main.js',
output: {
filename: 'kendo-bundle.js',
path: path.resolve(__dirname, 'wwwroot/libs/kendo/dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [{ loader: 'style-loader' }, { loader: 'css-loader' }]
},
{
test: /jquery.+\.js$/,
use: [{
loader: 'expose-loader',
options: 'jQuery'
}, {
loader: 'expose-loader',
options: '$'
}]
}
]
},
externals: {
jquery: 'jQuery'
}
}
}
What this will do is create a single js file that contains all of kendo, transpiled so you don't get 'module' errors. The use of expose-loader
, externals jquery
and the jquery rules are all there so that abp.io scripts, the way jquery is added and how kendo's js generally includes jquery doesn't conflict with each other.
- In the
abp.resourcemapping.js
file, add the necessary entries that look like the following:
module.exports = {
aliases: {
},
mappings: {
"@node_modules/@progress/kendo-ui/css/**/*": "@libs/kendo/css",
"@node_modules/@progress/kendo-ui/js/**/*": "@libs/kendo/js"
}
};
This will ensure the scripts and styles we need are packed up and in the right place for the next steps.
Run
yarn
(to get the package)Run
gulp
(to execute the mapping)Run
npm build
(to execute the conversion of the js from Telerik into something usable here)In the
TelerikComponents.Web
project, under/Bundling
, create a new directory we'll callKendo
- i.e./Bundling/Kendo
- In
/Bundling/Kendo
, create the class fileKendoScriptContributer.cs
with the following content:
namespace TelerikComponents.Web.Bundling
{
[DependsOn(
typeof(JQueryScriptContributor)
)]
public class KendoScriptContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/kendo/dist/kendo-bundle.js"); // This is the output of our webpack step
}
}
}
- In
/Bundling/Kendo
, create the class fileKendoStyleContributer.cs
with the following content:
namespace TelerikComponents.Web.Bundling
{
public class KendoStyleContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/kendo/css/web/kendo.common-bootstrap.min.css");
context.Files.AddIfNotContains("/libs/kendo/css/web/kendo.bootstrap-v4.min.css");
}
}
}
- In the
TelerikComponents.Web
project, under/Components
, create a new directory we'll callKendo
- i.e./Components/Kendo
- Create a
Default.cshtml
with the following content:
@using TelerikComponents.Web.Bundling.Kendo
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
<!-- Kendo -->
<abp-script type="typeof(KendoScriptContributor)" />
- Create a KendoViewComponent.cs with the following content:
public class KendoViewComponent : AbpViewComponent
{
public IViewComponentResult Invoke()
{
return View("/Components/Kendo/Default.cshtml");
}
}
- In
/Pages/_ViewImports.cshtml
add the tag helper:
@using Kendo.Mvc.UI
@addTagHelper "*, Kendo.Mvc"
- Finally, in your
TelerikComponentsWebModule.cs
file - let's add the following bits:- In
ConfigureServices
, addConfigureKendo(context.Services);
. The method implementation looks simply like this:
- In
private void ConfigureKendo(IServiceCollection services)
{
services.AddKendo();
}
- Find the area
Configure<AbpBundlingOptions>
and after theGlobal
add, also add our style contributor.AddContributors(typeof(KendoStyleContributor))
:
Configure<AbpBundlingOptions>(options =>
{
options
.StyleBundles
.Get(StandardBundles.Styles.Global)
.AddContributors(typeof(KendoStyleContributor)); // add this
});
If you don't see this section, add it to ConfigureServices()
.
* Add a new configure to setup a layout hook, where we add the kendo scripts to the bottom of the page:
Configure<AbpLayoutHookOptions>(options =>
{
options.Add(
LayoutHooks.Head.Last, //The hook name
typeof(KendoViewComponent) //The component to add
);
});
Step 2 - Checking the Setup
If we've done everything right, then we should now be able to use the components. On any page, you should now be able to use either the tag helpers or razor syntax:
<kendo-numerictextbox name="currency" format="c" min="0"
enable="true" max="100" value="30">
</kendo-numerictextbox>
@(Html.Kendo().NumericTextBox()
.Name("currency")
.Format("c")
.Min(0) // Set the min value of the NumericTextBox.
.Max(100) // Set the min value of the NumericTextBox.
.Value(30) // Set the value of the NumericTextBox.
)
Comments
Alper Ebiçoğlu 194 weeks ago
Thank you for the article! Telerik integration was a missing subject.
Kori Francis 194 weeks ago
Happy to help! We have TONS we can write about, as we migrate our solutions to abp.io.
Kori Francis 194 weeks ago
Source code for this project is located here: https://github.com/kfrancis/telerik-and-abpio
Halil İbrahim Kalkan 193 weeks ago
Thanks Kori for your article :)
Mattz1994 187 weeks ago
Typo warning; namespace TelerikComponets.Web.Bundling should be Components
Took my dyslexic self a while to find it
Kori Francis 187 weeks ago
Sorry about that! I've fixed it in the source article.
mel@quadsoftpa.com 186 weeks ago
I'm finding a real problem with this approach. While it works great (and easier to implement than previous approaches) the problem I'm having is the injection of +36k lines of kendo CSS AFTER all All the other CSS has been loaded. Typically I have an override file, which loads after Kendo styles to do my customizations. This doesn't work when default styles Kendo are loaded directly into the page.
Any thoughts on how to handle this?
PSTEELNZ 164 weeks ago
Could you not just add an overrides file to the end of the KendoStyleContributor?
Tm4eAbpDev 146 weeks ago
Thank you for sharing the article. You can update something the article
"use strict";
var gulp = require("gulp"), path = require('path'), copyResources = require('./node_modules/@abp/aspnetcore.mvc.ui/gulp/copy-resources.js');
exports.default = function(){ return copyResources(path.resolve('./')); };
Github link: https://github.com/kfrancis/telerik-and-abpio/blob/main/src/TelerikComponents.Web/gulpfile.js
ales 85 weeks ago
Hi, I dont't think this is valid solution since you can run into problems with pop-ups:
https://docs.telerik.com/blazor-ui/troubleshooting/general-issues?&_ga=2.79298260.1791779498.1681794651-1851969948.1674731373&_gl=1*j0t795*_ga*MTg1MTk2OTk0OC4xNjc0NzMxMzcz*_ga_9JSNBCSF54*MTY4MTc5NDY1MS42My4xLjE2ODE3OTcyNTUuMzMuMC4w#wrong-popup-position
Gary Medina 38 weeks ago
Good article, thank you! It would be appreciated if this could be extended to use something like a Grid or Scheduler where data is passed between. I'm stuck on the best approach and some functionality. Thanks again!