dashboard-404520-web-dashboard-create-dashboards-on-the-web-custom-request-headers.md
This topic describes how to pass custom request headers from the client to the server. It includes limitations, a general overview, and task-based examples.
To use the approach described in this topic in applications with the ASP.NET Web Forms Dashboard Control, set the control’s UseDashboardConfigurator property to true. For more information, refer to the following topic: Server-Side API Overview.
In the case of the Ajax remote service, the Web Dashboard Control uses form.submit for export operations. You cannot add custom headers for form.submit - use the Fetch remote service to add custom headers for export operations instead. For more information, refer to the following breaking change document: Web Dashboard — Export utilizes Fetch instead of jQuery Ajax.
To pass a value from the client to the server, use the FetchRemoteService.headers or AjaxRemoteService.headers property to add a record (a key/value object) to request headers:
onBeforeRender(e: DashboardControlArgs) {
this.dashboardControl = e.component;
this.dashboardControl.option('fetchRemoteService.headers', {
'Authorization': 'AuthToken123'
});
}
You can also use the FetchRemoteService.beforeSend or AjaxRemoteService.beforeSend callback to add a custom request header or modify predefined headers of the dashboard control.
The following snippets add a custom Authorization header to the request headers depending on the framework:
Angular
<dx-dashboard-control endpoint='http://localhost:5000/api/dashboard'>
<dxo-fetch-remote-service
[headers] = "headers">
</dxo-fetch-remote-service>
</dx-dashboard-control>
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
headers: { [key: string]: any } = { "Authorization": "AuthToken123" };
}
For more information on property binding in Angular applications, refer to the following topic: Property Binding in Angular.
React
import React from 'react';
import './App.css';
import DashboardControl, { FetchRemoteService } from 'devexpress-dashboard-react';
const headerAuth = { "Authorization": "AuthToken123" };
function App() {
return (
<div style={{ position : 'absolute', top : '0px', left: '0px', right : '0px', bottom: '0px' }}>
<DashboardControl style={{ height: '100%' }}
endpoint="http://localhost:5000/api/dashboard">
<FetchRemoteService
headers = { headerAuth }/>
</DashboardControl>
</div>
);
}
export default App;
For more information on how to change control properties in React applications, refer to the following topic: Change Control Properties.
Vue
<template>
<div>
<DxDashboardControl
style="height:900px; display: 'block'; width: '100%';"
endpoint="http://localhost:5000/api/dashboard">
<DxFetchRemoteService
:headers="{ 'Authorization': 'AuthToken123' }">
</DxFetchRemoteService>
</DxDashboardControl>
</div>
</template>
<script>
import { DxDashboardControl, DxFetchRemoteService } from 'devexpress-dashboard-vue/dashboard-control';
export default {
components: {
DxDashboardControl,
DxFetchRemoteService
}
}
</script>
For more information on property binding in Vue applications, refer to the following topic: Property Binding in Vue.
The following example implements authentication based on JWT for ASP.NET Core Dashboard Control. The FetchRemoteService.headers property is used to pass authorization token from the client to the server:
const tokenKey = "accessToken";
function onBeforeRender(sender) {
var dashboardControl = sender;
const token = sessionStorage.getItem(tokenKey);
dashboardControl.remoteService.headers = { "Authorization": "Bearer " + token };
}
This example uses dashboard parameters to update data in a specific dashboard item without refreshing the entire dashboard. The approach allows you to avoid performance delays.
In this example, a user can select a row in the Products grid item. This product selection defines the filter criteria for the Sales per Product chart:
The headers property stores a ProductId value and sends it to the server:
function onItemMasterFilterStateChanged(dashboardControl, e) {
if (e.itemName === 'gridDashboardItem1') {
var viewerApi = dashboardControl.findExtension('viewerApi');
var filterValues = viewerApi.getCurrentFilterValues(e.itemName);
if (filterValues) {
var slice = viewerApi.getItemData(e.itemName).getSlice(filterValues[0].getAxisPoint());
var productIdMeasure = slice.getMeasures().filter(m => m.dataMember === 'ProductID')[0];
var productId = slice.getMeasureValue(productIdMeasure.id).getValue();
// Send a ProductId value to the server using Request Headers
dashboardControl.remoteService.headers = { 'ProductId': productId };
// Refresh the Chart Dashboard Item
dashboardControl.refresh(['chartDashboardItem1']);
}
}
}
On the server side, pass the obtained ProductId value to the dashboard parameter collection in the CustomParameters event handler. The change of the ProductIdParameter value results in requesting filtered data from the server:
// ...
configurator.SetConnectionStringsProvider(new DashboardConnectionStringsProvider(configuration));
// ...
var contextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
configurator.CustomParameters += (s, e) => {
var value = Convert.ToInt32(contextAccessor?.HttpContext?.Request.Headers["ProductId"].FirstOrDefault());
e.Parameters.Add(new DashboardParameter("ProductIdParameter", typeof(int), value));
};
The following example filters data when the dashboard control operates in Designer mode. In this mode, the control displays only several records from the data source to improve performance.
On the client, the onOptionChanged event is handled to catch working mode changes. Pass the working mode to the server through the FetchRemoteService.headers property. The DashboardControl.reloadData method call initiates data reloading:
function UpdateDashboardData() {
dashboardControl.remoteService.headers = { "DashboardWorkingMode": dashboardControl.option("workingMode") };
dashboardControl.reloadData();
}
The DashboardWorkingMode value from the request header is used to filter data when the dashboard control is in Designer mode:
// ...
// Applies dynamic filter in the Designer working mode for the DashboardObjectDataSource.
configurator.DataLoading += (s, e) => {
var contextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
var workingMode = contextAccessor.HttpContext.Request.Headers["DashboardWorkingMode"];
if (e.DashboardId == "Object" && e.DataId == "odsInvoices") {
var data = Invoices.CreateData();
if (workingMode == "Designer")
e.Data = data.Where(item => item.Country == "USA");
else
e.Data = data;
}
};
The following example switches between database connections from the Web Dashboard UI using two custom buttons.
When a user clicks a button, use the headers property to pass a custom header with the corresponding database connection ID (nwind/nwind2). After that, call the DashboardControl.reloadData method to reload data:
e.items.unshift({
widget: 'dxButton',
options: {
text: 'DB1',
type: 'default'
},
onClick: () => {
dashboardControl.option('fetchRemoteService.headers', { "database": "nwind" });
dashboardControl.reloadData();
}
}, {
widget: 'dxButton',
options: {
text: 'DB2',
type: 'default'
},
onClick: () => {
dashboardControl.option('fetchRemoteService.headers', { "database": "nwind2" });
dashboardControl.reloadData();
}
});
On the server, use an IHttpContextAccessor object to access the passed parameter value (database connection ID) in the ConfigureDataConnection event handler:
// ...
configurator.ConfigureDataConnection += (s, e) => {
if (e.ConnectionName == "nwind") {
IHttpContextAccessor httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
IHeaderDictionary headers = httpContextAccessor.HttpContext.Request.Headers;
string dbKey = headers.ContainsKey("database") ? headers["database"] : "nwind";
string connectionString = dbKey switch {
"nwind" => "XpoProvider=InMemoryDataStore;Read Only=true;Data Source=Data\\nwind.xml",
"nwind2" => "XpoProvider=InMemoryDataStore;Read Only=true;Data Source=Data\\nwind2.xml",
_ => throw new ArgumentOutOfRangeException("Incorrect database name")
};
e.ConnectionParameters = new CustomStringConnectionParameters(connectionString);
}
};
See Also