Data Feature overview
The App Builder Data features let users add, edit and use external data source in the application they are developing. By default, the App Builder comes with a mock Northwind data source which users can use for reference. Below you can find different ways to set up Rest API data sources:
- By using a Rest API URL with the data source.
- By using a Swagger URL or file definition (json/yaml).
Warning
Using a JSON type data source with file upload is now deprecated
If you have uploaded data sources in your application prior the removal of the 'Upload .json file' functionality, you will be notified that the request "Failed to retrieve from 'X' and is now switching to mock data response".
Failed to retrieve data from previously uploaded file
All added data sources are placed in the data toolbox and users can expand/collapse each data source in order to see the included tables and selected fields.
The App Builder also supports nested collection inside a response object. You can now bring in APIs that wrap the return collection in a metadata object (e.g. oData and others) and use the nested collection for data-binding components such as the Grid or to perform repeat operations based on it.
Nested Collection Demo
Adding a data source
The App Builder Data feature enables users to link to external publicly available source(Rest API)
Note
Data sources added to the App Builder are restricted to the user space and are visible only to the user that added them, or to their team space (when the teams feature is available).
Adding data source from a URL
Adding a Swagger data source
The power of Swagger tools starts with the OpenAPI Specification — the industry standard for RESTful API design.
You can now specify a Swagger definition (by providing a file URL or simply upload it) and an intuitive design will help you pick an endpoint an data fields, with ease. You can later on bind this data source to a component like Grid, Card, List or any other bindable component.
Check out the full article on how to add a Swagger definition and bind your data to it.
Swagger demo
Using data source from local network sources
You can now make requests to a localhost or private networks. This includes regular REST endpoints and Swagger endpoints.
Local network sources usage
If you get an error dialog while using a private network this section can help resolve the problem. If the problems aren't resolved, follow the report and issue or send us feedback section.
Request failed error dialog
Due to the essence of working with local networks this type of error requires additional work in order to identify if the local/private service fails due to CORS problems (Cross-Origin Requests) or else.
If Request failed
dialog appears while you add a local service, open the dev tools
of your browser (Hit F12
) and check the console/network tab for errors. The most probable reason would be CORS restrictions.
Request failed error
Based on the local service configuration, there are some ways to overcome the Cross-Origin Requests problem that we discuss with more details below.
Enable Cross-Origin Requests (CORS) in ASP.NET Core
This article shows how to enable CORS in an ASP.NET Core app. You can ensure that the Web App builder adds CORS policy that Allows all
or specific
origins:
var builder = WebApplication.CreateBuilder(args);
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.AllowAnyOrigin();
});
});
Set .UseCors() right after the app
initialization.
var app = builder.Build();
app.UseCors(MyAllowSpecificOrigins);
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
Enable CORS Using IIS Manager, web.config or C#
Follow the steps below in order to enable access to your internally hosted data source using IIS.
- Open IIS manager on your server or on your local PC.
- Navigate to the website you need to edit the response headers for.
- From the list or Icons related to the site you are editing, select "HTTP Response Headers" from the middle-pane, as shown in the image below
- Double click "HTTP Repsonse Header"
- Now, click "Add" from right hand side pane
- A dialog box will open. For name enter "Access-Control-Allow-Origin" and for Value enter an asterisk (*).
- Click Ok, you are done.
IIS Configuration
You can simply enable CORS by adding configuration in your asp.net website's web.config file or adding some code in your global.asax file. Detailed information here.
OpenAPI (Swagger) endpoints are grayed out
This usually means that the endpoint does not have a defined response or that the response type is unsupported.
This can happen if your API does not provide enough information to Swagger to create a proper response description.
Example of an endpoint that does not work with App Builder:
Note that it describes a 200
"text" response with no other type information in it.
Example of an endpoint with enough information to work with App Builder:
Note that the endpoint describes a 200
response with an example of the return type.
Describing response on .Net Controller API
// Wrong: it doesn't provide enough information to describe the response type as it's not using generics
[HttpGet]
public async Task<ActionResult> GetCategories()
{
return Ok(await categoriesService.GetCategories());
}
// Good: it describes the return type using generics
[HttpGet]
public async Task<ActionResult<IEnumerable<Category>>> GetCategories()
{
return Ok(await categoriesService.GetCategories());
}
Describing response on .Net Minimal API
// Wrong: it doesn't provide enough information to describe the response type as Results.Ok() is not generic
app.MapGet("/category", async () => Results.Ok(await categoriesService.GetCategories()));
// Good: It's using `TypedResults`
app.MapGet("/category", async () => TypedResults.Ok(await categoriesService.GetCategories()));
// Good: It describes the response type with `.Produces<>()`
app.MapGet("/category", async () => Results.Ok(await categoriesService.GetCategories()))
.Produces<IEnumerable<Category>>();
// Good: It's returning the raw generic object (not wrapped in Result)
app.MapGet("/category", async () => await categoriesService.GetCategories());
Selecting data fields and changing fields type
When a data source has been added, users can connect a particular data field to a component section. In order for this to be done, first select the component (a card component is used in the example below), then change Repeat mode to Data and scroll down the menu to locate and select the table from the Data Source that you want to connect to. Finally, connect the card section with the selected table field.
Selecting data fields
Changing a data source table field type
Connecting Data Source to a repeated component
When a data source has been added, users can connect a particular data field to a component section. In order for this to be done, first select the component (a card component is used in the example below), then change Repeat mode to Data and scroll down the menu to locate and select the table from the Data Source that you want to connect to. Finally, connect the card section with the selected table field.
Connect a data source table field to a component section
Hierarchical Binding Support
Now you can bind a component to a hierarchical data structure and bind nested data-context collections with data repeat.
Let's look at the following datasource having three data levels, Movies -> Cast -> Films:
{
"name":"Movies list",
"movies":[
{
"title":"The Dark Knight",
"cast":[
{
"name":"Christian Bale",
"character":"Bruce Wayne/Batman",
"films":[
{
"title":"American Psycho",
"role":"Patrick Bateman"
},
{
"title":"The Prestige",
"role":"Alfred Borden"
}
]
},
{
"name":"Heath Ledger",
"character":"The Joker",
"films":[
{
"title":"Brokeback Mountain",
"role":"Ennis Del Mar"
},
{
"title":"The Imaginarium of Doctor Parnassus",
"role":"Ennis Del Mar"
},
{
"title":"The Imaginarium of Doctor Parnassus",
"role":"Tony"
}
]
}
]
},
...
]
}
You can now bind a repeater to the nested data by using the data context. Movies -> Cast collection
Data context
And even go deeper one more level to the Cast -> Films collection
Data context one level deeper
The end result with the above hierarchical data source would be:
Hierarchical binding result
It is also applicable to components like Tree and other containers. The example below is showing how a simple Tree and Tree Grid can bind to data sources with hierarchical structure.
Nested repeaters example
Lets review the Tree component, you will notice how we use the Repeat Data option in order to bind the root and child elements to a specific hierarchy level. As the Tree is declarative component, and it does not have data input binding (at tree root level), we declare it by specifying the node hierarchy and iterating through the hierarchical data set. Nodes should be bindable to a data model so that their expanded and selected states are reflected in the underlying data as well.
Known issues and limitations
Unable to infer schema from data
This error message will be show when the size of the parsed table schema of the datasource is too big (over 5mb). It can be triggered when:
- Adding a regular REST endpoint.
- When checking endpoints of a swagger datasource.
- Or when datasource is updated.
Keep in mind this is not a restriction on the data, for example it can be with more than 50MB of rows, although as long as the *schema (note below) can be represented in under 5MB, the App Builder will load it.
Note
Schema: The shape of the data for all the tables of the datasource
Unable to infer schema from data
Download/Upload definition from local network source
Downloaded OpenAPI files dot not contain server URL information and it cannot infer the server base address. This will happen if you do not specify the localhost URL directly through the Add URL source and instead Upload it as definition, you will get an empty Base URL.
Missing Base URL
In order to overcome this problem you should add the server base address relative to the server's host in your Solution/Program.cs
file
app.UseSwagger(c =>
{
c.PreSerializeFilters.Add((swagger, httpReq) =>
{
// Adding server base address in the generated file relative to the server's host
swagger.Servers = new List<OpenApiServer> { new OpenApiServer { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}" } };
});
});
Additional Resources
- App Builder Components
- App Builder Interface Overview
- Single Page And Navigation
- App Builder Components
- Flex Layouts
- Running Desktop App
- Generate app