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.

  1. 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.
  2. Uncomment the Sum method. Now you can invoke that method from Radzen.
  3. Drag and drop a Button component in a Radzen page.
  4. 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 and y parameters of the Sum method.
  5. 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? The result keyword is a placeholder which means “the result of the current custom method”. Then sum 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:

  1. When you click the button the event handler executes the custom Sum method with parameters x=1 and y=2 by making a HTTP request.
  2. The Sum method returns the sum of its arguments in JSON format.
  3. 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.

  1. Create two page properties - x and y. They will store the user input and be the arguments of the Sum method.
  2. Drag and drop two numeric components. Data-bind the first component to x and the second to y.
  3. Edit the Click event handler of the button from the previous section. Set the x parameter to ${x} and the y parameter to ${y}. This will use the values of the x and y 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.

  1. Add a new MSSQL data source for the Northwind database. You can check the MSSQL help topic for additional instructions.
  2. Run the application to generate the required code - model classes, Entity Framework context etc.
  3. Open the server\Controllers\ServerMethodsController.cs (or ServerMethodsController.vb) file in your favorite text editor.
  4. 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
      
  5. 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
      

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:

  1. Create a new page in your application.
  2. Drag and drop a TextBox and a Button.
  3. Create a page property called country and data-bind the TextBox to that property.
  4. 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}.
  5. 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.

  1. Make sure you have a MSSQL data source for the Northwind database.
  2. Import the Newtonsoft.Json and Newtonsoft.Json.Serialization namespaces.
    • C#
      using Newtonsoft.Json;
      using Newtonsoft.Json.Serialization;
      
    • VB
      Imports Newtonsoft.Json
      Imports Newtonsoft.Json.Serialization
      
  3. 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
      
  4. Create a new page in Radzen.
  5. Drag and drop a DataGrid component.
  6. Add two columns to the DataGrid.
    • Set Property of the first column to ShipCity (you have to type it in). Set Title to City.
    • Set Property of the second column to Count. Set Title to Orders.
  7. Add a new event handler for the Page Load event.
    • Set Type to Invoke custom method
    • Pick the OrdersByCity method.
  8. 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}.
  9. 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.

  1. First create a new directory which will store the uploaded files - server\wwwroot. The wwwroot 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.
  2. 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
      
  3. Inject an instance of the IHostingEnvironment service in the constructor of the ServerMethodsController class. This service provide the file system location of the wwwroot 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
      
  4. 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
      
  5. Create a new Radzen page.
  6. Drag and drop an Upload component.
  7. 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}.
  8. 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 the UploadFiles 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);
   }