DotNetT Light_870x220

Here’s a Blazor Component that uses C# to retrieve data from a Web Service and display it in the new Blazor-Enabled KendoGrid. To put it another way: Client-side updates with no JavaScript required.

As you'll see here, thanks to the Telerik UI for Blazor Early Preview, you can already start using Telerik UI components in a Blazor environment. The biggest problems you'll have in using this technology is creating the environment that it runs in – the components themselves just work as advertised.

Setting Up

Fundamentally, this is all preview technology so you're going to need to use both the previews for Visual Studio 2019, and .NET Core 3.0 SDK.

Once you've installed those downloads, you'll create your project by starting up Visual Studio 2019 Preview and selecting Create a New Project from the choices on the right of the initial dialog. In the ‘Create a new project' dialog that appears, select ASP.NET Core Web Applications and click the Next button. The next dialog will let you name your project (among other configuration options). Click the Create button after you're done with this page and (finally!) pick the kind of project you want to create. To work with Blazor, you'll want to use the Razor Components template, so select it, and click the Create button to initialize your project in its solution.

This is your first opportunity to check that you've successfully installed the right “bundle of everything”: If your Visual Studio solution contains a single project that has, in its Components/Pages folder, files with the .razor extension, then you've got the right combination of Visual Studio and .NET Version 3.0.

Razor Components aren't “true” Blazor in the sense that you'll have C# code running in the browser. Instead, Razor Components execute your C# code on the server and use SignalR to communicate between the client and server. This obviously limits the scalability of your application compared to fully executing all code on the client. However, it also avoids the two megabyte download that “Blazor on the client” currently requires (and, to be fair, in ASP.NET Core with the right topology, the scaling limit for SignalR is pretty high). The major benefit of experimenting with Razor Components is that it's an official technology that's included in .NET Core 3.0, while “Blazor on the client,” despite being in version 0.9.0, is still — and I'm quoting Microsoft here — in “pre-alpha.” However, the code and HTML in this post should work as-is with “Blazor on the Client” when (or if) that technology comes out of alpha.

The one wrinkle that I found after I got everything set up was that I would make changes to my code and it would make no difference to my running application until I selected Build | Rebuild Solution. If you get tired of constantly requesting rebuilds (or, as I did, just kept forgetting to do it) then the simplest solution is to trigger a rebuild every time you debug in every project by going to Tools | Options | Projects and Solutions | .NET Core and unchecking the Up to Date Checks option. If that solution seems too heavy-handed to you, then you can fix the problem for the project you're working on by going into the project's .csproj file and adding this:

<ItemGroup>
  <UpToDateCheckInput
    Include="@(Content->WithMetadataValue('Extension', '.razor'))" />
</ItemGroup>

You're now ready to add the Telerik components to your project. The Telerik team, not surprisingly, provides the best description of how to set up your application to use the new Blazor-enabled components. You'll also need to tweak your project file.

Hey, no one said that exploring the future of technology was going to be easy.

The Case Study

For the case study I'm going to use here, I added a second ASP.NET Core API project to my solution. This Web Service will provide a set of Customer objects. I defined my Customer object in another Class Library (.NET Standard) project that I referenced from both my Razor Components and API project. I added both of these other projects just by right-clicking on the Solution node in Solution Explorer and selecting Add | New Project.

My Customer class is ridiculously simple:

namespace Customers.Common
{
  public class Customer
  {
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
  }
}

And my API class wasn't much more complicated. I created a List of Customer objects in the constructor for a controller class (cleverly called Customers) and returned that collection from my controller class's Get method:

[Route("Customers")]
[ApiController]
public class Customers : ControllerBase
{
  List<Customer> custs = new List<Customer>();
  public Customers()
  {
    custs.Add(new Customer
    {
      Id = 1,
      FirstName = "Peter",
      LastName = "Vogel"
    });

    // more customers added
  }

  [HttpGet]
  public ActionResult<IEnumerable<Customer>> Get()
  {
    return custs;
  }
}

I also set up the Solution to start debugging with two Startup projects by right-clicking on the Solution node, picking Set Startup Projects and selecting the ‘Multiple startup projects' option in the resulting dialog. In the list of projects that follow that option, I set the Action dropdown list to “Start” for both my Razor Components project and my API project before clicking the OK button.

Creating the Blazor UI

If you've put all that in place, then you're ready to create a Razor Components page that uses the KendoGrid to display a list of Customer objects retrieved from a Web Service. To add the page, right-click on the Razor Components' project's Components/Pages folder and select Add | New Item. Unfortunately, the Add New Item dialog currently doesn't include a template that generates a Razor Components class. However, if you select the Razor View template and set the file name to end with the .razor extension, everything will work out fine (it's the .razor extension that defines a Razor Component). I called my file DisplayCustomers.razor.

At the top of my Razor component, I set the URL path to retrieve this component, added the namespace for the Class Library holding the definition of my Customer class, and enabled the Tag Helpers in the Kendo.Blazor namespace (I could also have done that last step in one of my project's _ViewImports files). Here's what that looked like:

@page "/displaycustomers"
@using Customers.Common
@addTagHelper *,Kendo.Blazor

Within my page, I added a header and used the Kendo Tag Helpers to define my KendoGrid. This gives you another checkpoint to see if you've got the “bundle of right stuff”: If your KendoGrid tags aren't in boldface, then the Telerik.UI.for.Blazor NuGet package didn't get installed correctly.

<h1>List Customers</h1>

<KendoGrid Data=@customers Sortable=true>
  <KendoGridColumns>
    <KendoGridColumn Field="Id" Title="Customer Id" />
    <KendoGridColumn Field="FirstName" Title="First Name" />
    <KendoGridColumn Field="LastName" Title="Last Name" />
  </KendoGridColumns>
</KendoGrid>

This grid is attached to a field in my Razor Component that will provide the data for the grid to display (I also turned on automatic sorting because, well, why not?). I've defined three columns in my grid, one for each of the three properties on my Customer object. I also set the title for the columns those properties are displayed in.

Now, I need to define the field that will hold that data. That code looks like this:

@functions {
  private IEnumerable<Customer> customers = null;
}

At this point, all the page will do is display a blank grid. To start retrieving the data from the Web Service, I need, in my component's functions block, to override the component's OnInitAsync method. That method is automatically run as part of initializing the component as it's displayed, so it's a good place to do any initialization for the component. Rather than load a lot of code into the OnInitAsync method, I'll put the code that does all the work in a separate method that I'll call GetCustomers:

@functions {
  private IEnumerable<Customer> customers = null;
  protected override Task OnInitAsync()
  {
    GetCustomers();
    return base.OnInitAsync();
  }
}

For that GetCustomers method, I just write C# code, leveraging the .NET Core APIs. I added this method right below my OnInitAsync method:

public async void GetCustomers()
{
  HttpClient hc = new HttpClient();
  HttpResponseMessage rm =
    await hc.GetAsync("https://localhost:5001/customers");
  customers =
    await rm.Content.ReadAsAsync<IEnumerable<Customer>>();
  StateHasChanged();
}

To use the ReadAsAsync method to call my service, I had to add a NuGet package to my project (Microsoft.AspNet.WebApi.Client). But, I'll point out, that's just another C# package.

Really, only the call at the end of the method to the Razor Component's StateHasChanged method shows that this code is updating client-side resources. The StateHasChanged method notifies Blazor that the client's DOM has been updated which, in turn, causes Blazor to compare the updated DOM to what the user is currently seeing, figure out what's different, and update the user's view to reflect the loaded data.

And there's the beauty of Blazor: efficient client-side updates without a line of JavaScript and with access to the full .NET Core API. My client-side toolkit has suddenly gotten much more focused.

The full project referenced in this article can be found here.

For More on Telerik UI for Blazor

To learn more about Telerik UI for Blazor and download the preview, don't forget to check out this introductory blog post or visit the product page here.


Peter Vogel
About the Author

Peter Vogel

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter also writes courses and teaches for Learning Tree International.

Related Posts

Comments

Comments are disabled in preview mode.