Kentico Xperience 13 Beta 3 - New Data Access APIs
Tags: kentico, csharp, dotnetcore, kenticoxperience
Published: 2020-08-04 16:02:45

---
title: Kentico Xperience 13 Beta 3 - New Data Access APIs
published: true
description: Learn how to use the upcoming changes to data access in Kentico Xperience 13.
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/vk47s1w9y4uqjh7dh7en.jpg
tags: kentico, csharp, dotnetcore, kenticoxperience
series: Kentico Xperience 13 Beta
---

The Kentico Xperience 13 Betas let us, the development community, get access to the latest upcoming features in the next version of Kentico Xperience.

Beta 3 is now available. So let's dive in 🤽🏾‍♀️!

---

## How to Get the Kentico Xperience 13 Beta

To get access to the beta we need to have a DevNet account. If you don't have one, you can [register here](https://devnet.kentico.com/register).

After logging into DevNet with our account, we can download the beta in the [downloads section of the site](https://devnet.kentico.com/download/beta/kentico-xperience-13-milestone-3-beta).

The beta has instructions 📃 on how to get it up and running, what features are new in this version, the list of known issues, and what the focus should be for developers and users of Kentico Xperience when trying out this version of the beta.

---

## Data Access in Kentico Xperience 13

There are many new cool 😎 features and changes coming in Kentico Xperience 13, and I've already covered the support for ASP.NET Core and some of the new Page Builder architecture when targeting .NET Core...

{% post seangwright/kentico-ems-2020-beta-beta-2-on-net-core-494b %}

{% post seangwright/kentico-xperience-13-beta-3-page-builder-view-components-in-asp-net-core-onm %}

As excited 😃 as I am to be finally building Kentico Xperience sites with ASP.NET Core, I don't want to overlook some of the biggest low-level improvements to Xperience - changes to `DataQueryBase`/`ObjectQueryBase` and Xperience's data access APIs.

### Interfaces vs Static Methods

Up until now, the standard pattern for accessing strongly typed data in Xperience has been to use the various `*InfoProvider` class static methods 🧐.

For example, to get the collection of all Sites running in the application we would write the following:

```csharp
IEnumerable<SiteInfo> sites = SiteInfoProvider
    .GetSites()
    .AsEnumerable();

foreach (SiteInfo site in sites)
{
    Debug.WriteLine(site.SiteName);
}
```

The `static` nature of `GetSites()` means we don't have to instantiate a `SiteInfoProvider` to query the database.

This means we can query it wherever we want 😉! 

![](https://media.giphy.com/media/sHytgXD2vlNVC/giphy.gif)
<figcaption>Much wow, such ease!</figcaption>

This was great in a WebForms world where object construction often relied on factory patterns and data access code was commonly found directly in the presentation layer (`.aspx.cs` and `.ascx.cs` files).

In ASP.NET Core, [Dependency Injection](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1) is the law of the land.

The framework is designed to be testable, pushing [volatile dependencies](https://www.fortech.ro/dependency-injection-net-framework/) to outside of the application and instead relying on abstractions supplied via constructor parameters 💪🏽.

To accommodate this architectural shift, Xperience has changed the way data is accessed:

```csharp
IEnumerable<SiteInfo> sites = SiteInfo
    .Provider
    .Get()
    .AsEnumerable();

foreach (SiteInfo site in sites)
{
    Debug.WriteLine(site.SiteName);
}
```

This looks very similar, but there is a key different - we are using the `.Provider` property on `SiteInfo` 🤨.

This property is typed as:

```csharp
public interface ISiteInfoProvider : 
    IInfoProvider<SiteInfo>, 
    IInfoByIdProvider<SiteInfo>, 
    IInfoByGuidProvider<SiteInfo>, 
    IInfoByNameProvider<SiteInfo>
```

And, just for reference, `IInfoProvider<TInfo>` is defined as:

```csharp
public interface IInfoProvider<TInfo> 
    where TInfo : AbstractInfoBase<TInfo>, new()
{   
    void Delete(TInfo info);
    ObjectQuery<TInfo> Get();
    void Set(TInfo info);
}
```

This means Kentico is exposing abstractions, like `ISiteInfoProvider`, to give us access to data querying, instead of concrete or static types 🤔.

When using these APIs in places where Dependency Injection is not available, our code won't look much different (though Unit Testing might be easier!).

However, when we need to perform data access in parts of the application where Dependency Injection is supported and configured, we can rely on the abstractions for querying.

The code below, if run in an ASP.NET Core app, doesn't require us to register the `ISiteInfoProvider` type with the Dependency Injection container - Xperience handles that for us 👏🏾:

```csharp
public class SiteController
{
    private readonly ISiteInfoProvider provider;

    public SiteController(ISiteInfoProvider provider) =>
        this.provider = provider;

    public IActionResult GetSites()
    {
        var sites = provider.Get().AsEnumerable();

        foreach (SiteInfo site in sites)
        {
            // ...
        }

        return View(...);
    }
}
```

This code is far easier to test and requires fewer of Xperience's unit testing ~~hacks~~ ... I mean, APIs 😅, compared to using the `static` `*InfoProvider` methods.

It should be noted that most of the CRUD (Create, Read, Update, Delete) `static` methods have been marked as `Obsolete` 😮 and it is recommended to use the new `*Info.Provider.Get/Set/Delete` methods instead.

### New DataQueryBase/ObjectQueryBase Methods

In addition to changing how we perform queries against the database, Xperience has also added new ways to get the results of those queries.

In previous versions, to force evaluation of the `ObjectQuery<T>` being built up, we would either start iterating over the query or call `.Result`, `.TypedResult`, or `.ToList()` to force an evaluation.

> Since `ObjectQueryBase` implements `IEnumerable` any query we build up, with all the various query extension methods, can be enumerated 🤓, which forces the query to be executed and resulting `DataSet` be populated.

This approach was fine, but most of the time what we really wanted was to:

- Force evaluation
- Choose between typed/untyped results
- Expose an `IEnumerable` since it's the simplest API for consumers
  - `.Result` returns a `DataSet` and `.TypedResult` returns an `InfoDataSet<T>` which has lots of properties we typically don't need 😑

Xperience now gives us some convenient methods to cut down on boilerplate and give us what we want:

```csharp
IEnumerable<IDataRecord> GetEnumerableResult();
IEnumerable<TInfo> GetEnumerableTypedResult();
```

`GetEnumerableResult()` gives us access to the `System.Data.IDataRecord` which is a bit friendlier than trying to get access to, or work with `DataRow`:

```csharp
// Before

IEnumerable<int> siteIds = SiteInfo.Provider.Get()
    // Forces immediate execution
    .Result
    .Tables[0]
    // Exposes an Enumerable
    .AsEnumerable()
    .Select(r => 
        ValidationHelper.GetInteger(r[nameof(SiteInfo.SiteID)], 0)
    );

// After

IEnumerable<int> siteIds = SiteInfo.Provider.Get()
    // Forces immediate execution and exposes and Enumerable
    .GetEnumerableResult() 
    .Select(r =>
        r.GetInt32(r.GetOrdinal(nameof(SiteInfo.SiteID)))
    );
```

For the strongly typed variation, `GetEnumerableTypedResult()`, we get to clean up a few lines as well 👍:

```csharp
// Before

IEnumerable<SiteInfo> sites = SiteInfo.Provider.Get()
    // Forces immediate execution
    .TypedResult 
    // Exposes an Enumerable
    .AsEnumerable();

// After

IEnumerable<SiteInfo> sites = SiteInfo.Provider.Get()
    // Forces immediate execution and exposes and Enumerable
    .GetEnumerableTypedResult();
```

These changes are small, but I like them because they improve the developer experience 🤗 and encourage consistent patterns.

### Async Querying!

> Update: 2020-08-13
>
> I should have double checked and tested my code 🤦‍♂️.
> While the async querying works fine for `ObjectQuery`, it throws exceptions when used with `DocumentQuery`.
> This is even noted in the comment for the method on `DocumentQueryBase<T>`:
>
> `// The method is not supported for document query and always throws a System.NotSupportedException.`
> 
> I have contacted Kentico support about this, as I think it's a bad design decision to add a base class method that always throws an exception in a child class.
>
> I was told the team is working on getting async querying implemented by the time of Xperience 13's release.
> 
> Let's hope they get it done 🤞🤞!

Back when Web Forms was developed, concurrency on the web wasn't a primary concern, but 10 years later, when `async`/`await` was introduced in C# 5, concurrent programming had become the best way to get web applications to scale.

Kentico Xperience's data access APIs were built for the world of Web Forms, so they always lacked Async integration and would block the HTTP request thread when querying the database 🙁.

The lack of Async data access has been resolved in Xperience 13 and we can now use `async`/`await` all the way from our Controller Actions to the database call and back 😁.

![](https://media.giphy.com/media/2nwTda1ewYssE/giphy.gif)
<figcaption>This is how I feel when writing Xperience async queries</figcaption>

The two APIs we care most about are defined on `DataQueryBase`/`ObjectQueryBase` and since `DocumentQueryBase` inherits `ObjectQueryBase` and `DataQueryBase`, we can Async query for documents as well:

```csharp
.GetEnumerableResultAsync();
.GetEnumerableTypedResultAsync();
```

These are the Async equivalents of the methods we looked at already.

So what does Async querying look like in Xperience 13?

```csharp
public class SiteController
{
    private readonly ISiteInfoProvider provider;

    public SiteController(ISiteInfoProvider provider) =>
        this.provider = provider;

    public async Task<IActionResult> GetSites()
    {
        var sites = await provider
            .Get()
            .GetEnumerableTypedResultAsync();

        // ...

        return View(...);
    }
}
```

![Picard clapping](https://media.giphy.com/media/a0Lgc1JvbfS4o/giphy.gif)

### Providers as Repositories

With the new `IInfoProvider<TInfo>` (and related interfaces) APIs, we now have a consistent set of methods we use for query, independent of the type:

![Intellisense list of ISiteInfoProvider methods](https://dev-to-uploads.s3.amazonaws.com/i/prkolv3zat9lic3073xz.jpg)

We no longer have to use `SiteInfoProvider.GetSites()` for sites but `UserInfoProvider.GetUsers()` for users.

Instead, both look like this:

```csharp
SiteInfo.Provider.Get();
UserInfo.Provider.Get();
```

Here's a list of all the new, standard, methods:

```csharp
ObjectQuery<TInfo> Get();
TInfo Get(int id);
TInfo Get(string name);
TInfo Get(Guid guid);

Task<TInfo> GetAsync(int id, CancellationToken token);
Task<TInfo> GetAsync(string name, CancellationToken token);
Task<TInfo> GetAsync(Guid guid, CancellationToken token);

void Delete(TInfo info);
void Set(TInfo info); // handles both create and update
```

There's an implication here that might not be immediately obvious... 🤔

Xperience is now giving us [a set of Repositories](https://deviq.com/repository-pattern/) through a generic interface, instead of a bunch of data access initialization points.

Generic interfaces are great opportunities for cross-cutting concerns through [Decoration](https://andrewlock.net/adding-decorated-classes-to-the-asp.net-core-di-container-using-scrutor/).

I've covered some powerful ways to use Decoration with Xperience in my Design Patterns blog series, and I'm a huge proponent of the pattern for any cross-cutting, like logging or caching ✔.

{% post seangwright/kentico-12-design-patterns-part-12-database-query-caching-patterns-43hc %}

{% post seangwright/kentico-12-design-patterns-part-17-centralized-cache-management-through-decoration-2eo5 %}

> There are currently some technical limitations around decorating Xperience's built-in types due to some uses of type casting internally, but this could be fixed in the future.

Another implication of this repository pattern is that we don't need to make _another_ layer of repositories in our applications.

![](https://media.giphy.com/media/Ud5r7tzmG4De0/giphy.gif)

If you find you want to encapsulate common read/write scenarios, try the [Command / Query Pattern](https://www.dotnetcurry.com/patterns-practices/1461/command-query-separation-cqs) instead.

> My Design Pattern posts I linked above also cover the topic of Command / Query vs Repository 😉.

---

Xperience hasn't (as of yet) updated all the data access APIs, and some are still the same as before:

```csharp
// No Async, no new methods
int settingValue = SettingsKeyInfoProvider.GetIntValue("keyName");
```

But that doesn't mean we can't opt-into the new awesomeness seen elsewhere, if needed:

```csharp
SettingsKeyInfo setting = (await SettingsKeyInfoProvider
    .GetSettingsKeys()
    .WhereEquals(nameof(SettingsKeyInfo.KeyName), "someSetting")
    .TopN(1)
    .GetEnumerableTypedResultAsync())
    .FirstOrDefault()
```

---

## Conclusion

Kentico Xperience has always made it easy for developers to work with data created by the application and stored in the database.

We've been using the same powerful and flexible data access APIs for several years now.

With Xperience 13 we are gaining access to new ways of querying for data, including:

- Interfaces instead of static methods
- New `DataQueryBase`/`ObjectQueryBase` methods to clean up boilerplate
- Async querying
- Standardized interfaces and methods following a repository pattern

All of these new features are opt-in, though with some existing APIs being deprecated we might want to opt-in a little more aggressively for some of them.

When using Xperience 13 with ASP.NET Core, we will see the full benefit of these changes with Dependency Injection of providers and concurrent requests using `async`/`await`.

I find all of this very exciting (yes, I'm excited by new APIs 🤷‍♂️), and I'd love to hear your thoughts on how you might leverage the new features coming in Xperience 13.

As always, thanks for reading 🙏!

---

We've put together a list over on [Kentico's GitHub account](https://github.com/Kentico/Home/blob/master/RESOURCES.md) of developer resources. Go check it out!

If you are looking for additional Kentico content, checkout the Kentico tag here on DEV:

{% tag kentico %}

Or my Kentico blog series:

- [Kentico EMS: MVC Widget Experiements](https://dev.to/search?q=kentico%20ems%3A%20mvc%20widget%20experiements)
- [Kentico 12: Design Patterns](https://dev.to/search?q=Kentico%2012%3A%20Design%20Patterns)
- [Kentico CMS Quick Tips](https://dev.to/search?q=Kentico%20CMS%20Quick%20Tip)