As expressed in your feedback, token-based authentication functionality is crucial for JsonDataSource usage. This post describes how to implement this feature in v18.2 and then introduces our built-in implementation to be released with v19.1.
Implement Token-Based Authentication in v18.2
This section will cover two situations in which you might need this functionality:
- You are a report developer and want to bind a report to JSON data at runtime.
- You want to allow end-users to set up a connection using the Report Designer.
Bind to JSON Data at Runtime
First, create a UriJsonSource
descendant and override the GetJsonString
method, which downloads JSON data from the web service. Also, create two properties to store the user name and password:
public class MyUriJsonSource : UriJsonSource { public string Username { get; set; } [PasswordPropertyText(true)] public string Password { get; set; } public override string GetJsonString() { using(var client = new WebClient()) { client.Credentials = new NetworkCredential(Username, Password); return client.DownloadString(Uri); } } … }
Important note: The code snippet above implements basic HTTP authentication. You can modify it to enable token-based authentication. You can also rename or replace the properties that store login credentials:
public override string GetJsonString() { using(var client = new WebClient()) { client.Credentials = new NetworkCredential(Username, Password); // add header to request //client.Headers.Add(HeaderName, HeaderValue); return client.DownloadString(Uri); } }
Define a static class that will create a JsonDataSource
instance:
public static class MyJsonDataSourceHelper { public static JsonDataSource CreateCustomJsonDataSource(string uri, string username, string password) { var jsonDatasource = new JsonDataSource() { Name = "jsonDataSource", JsonSource = new MyUriJsonSource() { Uri = new Uri(uri), Username = username, Password = password } }; return jsonDatasource; } }
When designing a report, you can either use Embedded Fields (Mail Merge) or create report controls at runtime. Bind the report to data as shown below to see the result:
var report = CreateReport(); report.DataSource = MyJsonDataSourceHelper.CreateCustomJsonDataSource( @"http://northwind.servicestack.net/customers.json", "userName1", "userPassword1"); report.DataMember = "Customers"; new DevExpress.XtraReports.UI.ReportPrintTool(report).ShowPreview();
The complete implementation code is available on GitHub.
Modify End-User Report Designer
UI modification involves a few steps:
-
Customize the wizard pages and embed two additional editors. Use a custom
IWizardCustomizationService
interface implementation, as described in our Wizard Customization Overview documentation topic. -
Extend the
IChooseJsonSourcePageView
interface with UserName and Password properties. -
Implement a custom View that’s inherited from the
ChooseJsonSourcePageView
page . -
Make changes to the
ChooseJsonSourcePage<TModel>
presenter.
The following code showsa basic IWizardCustomizationService
implementation. (The complete source code is available on GitHub.)
public class MyWizardCustomizationService : IWizardCustomizationService, IJsonEditorsCustomizationService { public void CustomizeDataSourceWizard(IWizardCustomization<XtraReportModel> tool) { tool.RegisterPage<ChooseJsonSourcePage<XtraReportModel>, MyChooseJsonSourcePage<XtraReportModel>>(); tool.RegisterPageView<IChooseJsonSourcePageView, MyChooseJsonSourcePageView>(); } public void CustomizeReportWizard(IWizardCustomization<XtraReportModel> tool) { tool.RegisterPage<ChooseJsonSourcePage<XtraReportModel>, MyChooseJsonSourcePage<XtraReportModel>>(); tool.RegisterPageView<IChooseJsonSourcePageView, MyChooseJsonSourcePageView>(); } public void CustomizeWizard(JsonEditorId editor, IWizardCustomization<JsonDataSourceModel> tool) { tool.RegisterPage<ChooseJsonSourcePage<JsonDataSourceModel>, MyChooseJsonSourcePage<JsonDataSourceModel>>(); tool.RegisterPageView<IChooseJsonSourcePageView, MyChooseJsonSourcePageView>(); } public bool TryCreateDataSource(IDataSourceModel model, out object dataSource, out string dataMember) { dataSource = null; dataMember = model?.DataMember; return false; } public bool TryCreateReport(IDesignerHost designerHost, XtraReportModel model, object dataSource, string dataMember) { return false; } }
As you might have noticed, the code above implements the IJsonEditorsCustomizationService
interface. This is required if you want to enable custom wizard pages when end-users edit existing JsonDataSource
objects:
Next, implement a UriJsonSource
descendant as discussed in the previous section.
When end-users switch to the Preview tab, the DevExpress Reporting engine serializes the report layout. To add the new UserName and Password properties into serialized data, override the SaveToXml
/ LoadFromXml
methods as shown in the following code:
protected override void SaveToXml(XElement connection) { base.SaveToXml(connection); MySecretStorage.SecretStorage.Instance.SaveCredentials(Uri.Authority, new Tuple<string, string>(Username, Password)); } protected override void LoadFromXml(XElement connection) { base.LoadFromXml(connection); var cred = MySecretStorage.SecretStorage.Instance.GetCredentials(Uri.Authority); if(cred != null) { Username = cred.Item1; Password = cred.Item2; } }
The sample above uses a separate file to store property values. You can customize this code to meet your requirements.
Once the wizard is complete, the created data source object is copied from the wizard to the internal report model. A similar operation is carried out when you switch to the Preview tab in the End-User Report Designer. The Clone
method manages this behavior - which you can override as follows:
protected override JsonSourceBase Clone() { var clone = new MyUriJsonSource() { Uri = Uri, RootElement = RootElement, Username = Username, Password = Password }; return clone; }
Once all steps have been completed, the Report Designer will allow end-users to connect to the required data sources.
Authentication Enhancements in v19.1
The manual implementation described above will not be required once we ship v19.1 After you choose the Web Service Endpoint (URI) option in the wizard, you’ll see the following screen:
We provide three authentication options: Basic HTTP Authentication, Header Parameters and Query Parameters. The last option allows you to specify custom query string values to be passed with a web service request.
Your Feedback Counts
Let us know whether your use cases for such data sources are fully supported by our v19.1 implementation. We received a request to embed a predefined header parameters set into this wizard screen. We are also considering the capability to map report parameters to JsonDataSource
request parameters. We would love to learn more about your needs.
Please take a moment to cast your vote in the survey below.