Invoke custom method (Angular)
Quick video
Custom business logic is key to most applications - call a third party API, execute complex database query or perform some calculation and return its result.
Radzen provides out-of-the-box support for such cases via the Invoke custom method action type.
Invoking custom methods is supported in Angular applications that have server-support enabled and target the .NET Core 2.0 framework.
Introduction
All Radzen applications that have server-side support enabled contain a special file.
For C# applications it is server\Controllers\ServerMethodsController.cs
and for VB.NET it is server\Controllers\ServerMethodsController.vb
.
By default it contains just boiler-plate code and a sample custom method which is commented out.
Let’s try invoking that sample method in Radzen and display its result.
- Open the ServerMethodsController.cs or ServerMethodsController.vb file in your favorite text editor. If you cannot find those files then probably you haven’t run your Radzen application yet. Try running it so all code gets generated.
- Uncomment the
Sum
method. Now you can invoke that method from Radzen. - Drag and drop a Button component in a Radzen page.
- Handle the Click event of the Button.
- Set the Type of the action to Invoke custom method.
- Pick the custom method from the dropdown. Radzen will load all custom methods that you can invoke. If you don’t see your method yet - click the reload button next to the dropdown. In this case Radzen will display the
Sum
method. - Specify the arguments for the
x
andy
parameters of theSum
method.
- This will invoke the custom method. But we also need its result. Handle the
Then
event of the invoke.- Set the Type of the action to Show notification.
- Set Severity to info.
- Set Summary to
${result.sum}
. But what does${result.sum}
mean? Theresult
keyword is a placeholder which means “the result of the current custom method”. Thensum
is the property which our custom method happens to use to return its result.
Now run the application to test the Sum
method.
Here is what happened:
- When you click the button the event handler executes the custom
Sum
method with parametersx=1
andy=2
by making a HTTP request. - The
Sum
method returns the sum of its arguments in JSON format. - Radzen allows you to use the result of custom methods for various purposes - for example to display it as a notification.
Get user input
Now let’s pass the user input to the custom method. If you need a refreshment on getting user input in Radzen check the Properties help article.
- Create two page properties -
x
andy
. They will store the user input and be the arguments of theSum
method. - Drag and drop two numeric components. Data-bind the first component to
x
and the second toy
. - Edit the Click event handler of the button from the previous section. Set the
x
parameter to${x}
and they
parameter to${y}
. This will use the values of thex
andy
properties as method arguments.
Run the application to see it in action.
Perform custom database query
The previous examples used the sample custom method which doesn’t do anything particularly useful. Let’s do something real-life instead such as making a database query and returning its result. As usual we will use the Northwind database.
Create the custom method that executes the DB query
Let’s make the method return the number of orders that ship to a user specified country.
- Add a new MSSQL data source for the Northwind database. You can check the MSSQL help topic for additional instructions.
- Run the application to generate the required code - model classes, Entity Framework context etc.
- Open the
server\Controllers\ServerMethodsController.cs
(orServerMethodsController.vb
) file in your favorite text editor. - Inject the Entity Framework context created for the Northwind database as a constructor parameter of the ServerMethodsController class.
- C#
[Route("api/[controller]/[action]")] public class ServerMethodsController : Controller { private NorthwindContext northwind; public ServerMethodsController(NorthwindContext context) { this.northwind = context; } }
- VB
<Route("api/[controller]/[action]")> Public Class ServerMethodsController Inherits Controller Private northwind As Data.NorthwindContext Public Sub New(ByVal context As Data.NorthwindContext) Me.northwind = context End Sub End Class
- C#
- Add a new method to the ServerControllersMethod class. It will return the number of orders that ship to the specified country.
- C#
public IActionResult OrdersByCountry(string country) { var orders = northwind.Orders.Where(o => o.ShipCountry == country); return Json(new { count = orders.Count() }); }
- VB
Public Function OrdersByCountry(ByVal country As String) As IActionResult Dim orders = northwind.Orders.Where(Function(o) o.ShipCountry = country) Return Json(New With { .count = orders.Count() }) End Function
- C#
Create the UI
The UI will be simple:
- a textbox to capture the user input (the country)
- a button which will invoke the custom method and display the result
Follow these steps:
- Create a new page in your application.
- Drag and drop a TextBox and a Button.
- Create a page property called
country
and data-bind the TextBox to that property. - Handle the Click event of the Button.
- Set the action Type to Invoke custom method
- Pick the OrdersByCountry method from the dropdown.
- Set the
country
parameter to${country}
.
- Handle the Then event of the Invoke custom method to display the result.
- Set the action Type to Show notification.
- Set Severity to info.
- Set Summary to
Orders: ${result.count}
Run the application to try it:
Display DB query in a DataGrid
Another common task is to display the result of a custom DB query in a DataGrid. We will use again the Northwind database and will display the number of orders per ShipCity in a DataGrid component.
- Make sure you have a MSSQL data source for the Northwind database.
- Import the
Newtonsoft.Json
andNewtonsoft.Json.Serialization
namespaces.- C#
using Newtonsoft.Json; using Newtonsoft.Json.Serialization;
- VB
Imports Newtonsoft.Json Imports Newtonsoft.Json.Serialization
- C#
- Add a new method to the ServerMethodsController class
- C#
public IActionResult OrdersByCity() { var orders = northwind.Orders.GroupBy(o => o.ShipCity) .Select(group => new { ShipCity = group.Key, Count = group.Count() }); // Using DefaultContractResolver to preserve the property // name casing when serializing the result to JSON. return Json(new { value = orders }, new JsonSerializerSettings() { ContractResolver = new DefaultContractResolver() }); }
- VB
Public Function OrdersByCity() As IActionResult Dim orders = northwind.Orders.GroupBy(Function(o) o.ShipCity) _ .[Select](Function(group) New With { .ShipCity = group.Key, .Count = group.Count() }) ' Using DefaultContractResolver to preserve the property ' name casing when serializing the result to JSON. Return Json(New With { .value = orders }, New JsonSerializerSettings() With { .ContractResolver = New DefaultContractResolver() }) End Function
- C#
- Create a new page in Radzen.
- Drag and drop a DataGrid component.
- Add two columns to the DataGrid.
- Set Property of the first column to
ShipCity
(you have to type it in). Set Title toCity
. - Set Property of the second column to
Count
. Set Title toOrders
.
- Set Property of the first column to
- Add a new event handler for the Page Load event.
- Set Type to Invoke custom method
- Pick the OrdersByCity method.
- Handle the Then event of the Invoke custom action created in the previous step.
- Set Type to Set property. We want to store the result of the
OrdersByCity
method so we can use it with the DataGrid. - Set Name to ordersByCity.
- Set Value to
${result.value}
.
- Set Type to Set property. We want to store the result of the
- Finally set the Data property of the DataGrid to
${ordersByCity}
(click the gear icon to type that expression).
If you run the application you should see the following in your browser:
Upload files
Another common task that is easily doable with custom methods is handling file uploads.
- First create a new directory which will store the uploaded files -
server\wwwroot
. Thewwwroot
is a special directory - ASP.NET Core applications use it by default to serve static files. This will allow you to serve any uploaded without extra effort. - Import the following namespaces.
- C#
using System.Collections.Generic; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Newtonsoft.Json; using Newtonsoft.Json.Serialization;
- VB
Imports System.Collections.Generic Imports Microsoft.AspNetCore.Hosting Imports Microsoft.AspNetCore.Http Imports Newtonsoft.Json Imports Newtonsoft.Json.Serialization
- C#
- Inject an instance of the
IHostingEnvironment
service in the constructor of the ServerMethodsController class. This service provide the file system location of thewwwroot
directory.- C#
private readonly IHostingEnvironment hostingEnvironment; public ServerMethodsController(IHostingEnvironment hostingEnvironment) { this.hostingEnvironment = hostingEnvironment; }
- VB
Private ReadOnly hostingEnvironment As IHostingEnvironment Public Sub New(ByVal hostingEnvironment As IHostingEnvironment) Me.hostingEnvironment = hostingEnvironment End Sub
- C#
- Add a new method to the ServerMethodsController class which will save the files to some location.
- C#
[HttpPost] public IActionResult UploadFiles(IEnumerable<IFormFile> files) { var result = files.Select(file => { // Save the files in the default static file directory - wwwroot var path = Path.Combine(hostingEnvironment.WebRootPath, file.FileName); using (var stream = new FileStream(path, FileMode.Create)) { // Save the file file.CopyTo(stream); var request = HttpContext.Request; // Create the URL for the uploaded file var url = $"{request.Scheme}://{request.Host.Value}/{file.FileName}"; // Return the FileName and Url return new { FileName = file.FileName, Url = url }; } }).ToList(); // Return the file names and URL of the uploaded files return Json(new { value = result }, new JsonSerializerSettings() { ContractResolver = new DefaultContractResolver() }); }
- VB
<HttpPost> Public Function UploadFiles(ByVal files As IEnumerable(Of IFormFile)) As IActionResult Dim result = files.[Select](Function(file) ' Save the files in the default static file directory - wwwroot Dim filePath = Path.Combine(hostingEnvironment.WebRootPath, file.FileName) Using stream = New FileStream(filePath, FileMode.Create) ' Save the file file.CopyTo(stream) Dim request = HttpContext.Request ' Create the URL for the uploaded file Dim url = $"{request.Scheme}://{request.Host.Value}/{file.FileName}" Return New With { .FileName = file.FileName, .Url = url } End Using End Function).ToList() ' Return the file names and URL of the uploaded files Return Json(New With { .value = result }, New JsonSerializerSettings() With { .ContractResolver = New DefaultContractResolver() }) End Function
- C#
- Create a new Radzen page.
- Drag and drop an Upload component.
- Handle the Upload event of the Upload component
- Set Type to Invoke custom method.
- Pick UploadFiles as the method name.
- Set the files parameter to
${event.files}
.
- Handle the Then event of the Invoke custom method
- Set Type to Execute code
- Set Code to
console.log(${result.value})
. This will log the result of theUploadFiles
method to the browser console. In your actual application you can use the result for other purposes - assign it to a property, display it in a DataGrid or other component etc.
If you run the application and upload a file you should see similar output in the browser console:
Execute Stored Procedure
Add custom method to the partial class similar to previos chapter and invoke it when needed.
[Inject]
YourDbContext Context { get; set; }
public async Task<int> UspUpdateEmployeeHireInfos(int? someID, string someOtherParam)
{
SqlParameter[] @params =
{
new SqlParameter("@returnVal", SqlDbType.Int) {Direction = ParameterDirection.Output},
new SqlParameter("@someID", SqlDbType.Int) {Direction = ParameterDirection.Input, Value = someID},
new SqlParameter("@someOtherParam", SqlDbType.VarChar) {Direction = ParameterDirection.Input, Value = someOtherParam}
};
Context.Database.ExecuteSqlRaw("EXEC @returnVal=[YourSPSchema].[YourSP] @someID, @someOtherParam", @params);
int result = Convert.ToInt32(@params[0].Value);
return await Task.FromResult(result);
}