For my PowerBI custom visual I want to store some data in the storage. According to the documentation up to 1Mb are supported.
It works fine for just 3_000 zeros, but 30_000 zeros are failing with an undefined error.
I use the Developer Visual
to display my custom visual for debugging.
I tried storing data and then reading it (in the visual update) via:
public update(options: VisualUpdateOptions) {
//...
// try loading data
this.storageService.get("storage").then(data =>{
console.log("Loaded storage: ", data);
})
.catch(err=>{
console.error(err);
});
// remove any previous data
this.storageService.remove("storage");
// create sample data
let content = '0'.repeat(30_000);
// set storage data
this.storageService.set("storage", content).then(f =>{
console.log("Setting storage ... Finished!");
})
.catch(ex=>{
console.error(ex); // Line 102
});
//...
}
When saving the 30_000 character I get an "undefined" error:
visual.ts:102
undefined
(anonymous) @ visual.ts:102
(anonymous) @ customVisualsHost.bundle.min.js:12
(anonymous) @ visualsandbox.minimal.externals.min.js:146
c @ visualsandbox.minimal.externals.min.js:146
fireWith @ visualsandbox.minimal.externals.min.js:146
(anonymous) @ visualsandbox.minimal.externals.min.js:146
c @ visualsandbox.minimal.externals.min.js:146
fireWith @ visualsandbox.minimal.externals.min.js:146
i.reject @ customVisualsHost.bundle.min.js:12
e.RejectPromise @ customVisualsHost.bundle.min.js:20
m.handleSetStorageData @ customVisualsHost.bundle.min.js:20
m.executeMessage @ customVisualsHost.bundle.min.js:20
m.onMessageReceived @ customVisualsHost.bundle.min.js:20
(anonymous) @ customVisualsHost.bundle.min.js:20
n.invokeHandler @ customVisualsHost.bundle.min.js:19
n.dispatchMessage @ customVisualsHost.bundle.min.js:19
n.onMessageReceived @ customVisualsHost.bundle.min.js:19
windowMessageHandler @ customVisualsHost.bundle.min.js:19
dispatch @ visualsandbox.minimal.externals.min.js:146
v.handle @ visualsandbox.minimal.externals.min.js:146
postMessage (async)
n.sendMessage @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:16
n.postMessage @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:16
e.postMessage @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
V.setStorageData @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
e.setStorageData @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
e.onMessageReceived @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
(anonymous) @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
n.invokeHandler @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:16
n.dispatchMessage @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:16
n.onMessageReceived @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:16
windowMessageHandler @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:16
dispatch @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
v.handle @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
t.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
Ve.invokeTask @ web.min.386bab8ebb751022ba05.js:1
e.runTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
g @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
y @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
postMessage (async)
n.sendMessage @ customVisualsHost.bundle.min.js:19
n.postMessage @ customVisualsHost.bundle.min.js:19
t.setStorageData @ customVisualsHost.bundle.min.js:20
e.set @ customVisualsHost.bundle.min.js:19
update @ visual.ts:98
update @ customVisualsHost.bundle.min.js:19
(anonymous) @ customVisualsHost.bundle.min.js:19
t.trackVisualTime @ customVisualsHost.bundle.min.js:19
t.update @ customVisualsHost.bundle.min.js:19
(anonymous) @ customVisualsHost.bundle.min.js:19
(anonymous) @ customVisualsHost.bundle.min.js:19
(anonymous) @ customVisualsHost.bundle.min.js:19
(anonymous) @ customVisualsHost.bundle.min.js:19
n @ customVisualsHost.bundle.min.js:12
__awaiter @ customVisualsHost.bundle.min.js:19
(anonymous) @ customVisualsHost.bundle.min.js:19
(anonymous) @ customVisualsHost.bundle.min.js:19
(anonymous) @ customVisualsHost.bundle.min.js:19
(anonymous) @ customVisualsHost.bundle.min.js:19
(anonymous) @ customVisualsHost.bundle.min.js:19
n @ customVisualsHost.bundle.min.js:12
__awaiter @ customVisualsHost.bundle.min.js:19
o.executeSafelyAsync @ customVisualsHost.bundle.min.js:19
o.update @ customVisualsHost.bundle.min.js:19
m.fixUpdateOptionsAndUpdateVisual @ customVisualsHost.bundle.min.js:20
m.update @ customVisualsHost.bundle.min.js:20
m.executeMessage @ customVisualsHost.bundle.min.js:20
m.onMessageReceived @ customVisualsHost.bundle.min.js:20
(anonymous) @ customVisualsHost.bundle.min.js:20
n.invokeHandler @ customVisualsHost.bundle.min.js:19
n.dispatchMessage @ customVisualsHost.bundle.min.js:19
n.onMessageReceived @ customVisualsHost.bundle.min.js:19
windowMessageHandler @ customVisualsHost.bundle.min.js:19
dispatch @ visualsandbox.minimal.externals.min.js:146
v.handle @ visualsandbox.minimal.externals.min.js:146
postMessage (async)
n.flushQueue @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:16
e.ready @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
e.onIFrameLoad @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
(anonymous) @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
i @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
dispatch @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
v.handle @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
t.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
Ve.invokeTask @ web.min.386bab8ebb751022ba05.js:1
e.runTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
g @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
y @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
load (async)
R @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
t.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleEventTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
(anonymous) @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
add @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
(anonymous) @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
each @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
each @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
ke @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
one @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
e.initContainer @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
(anonymous) @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
i.<computed> @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
t.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
Ve.invokeTask @ web.min.386bab8ebb751022ba05.js:1
e.runTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
invoke @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
n.args.<computed> @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
setTimeout (async)
c @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
t.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleMacroTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
v @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
(anonymous) @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
A.i.<computed> @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.init @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
(anonymous) @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
t.invoke @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
Ve.invoke @ web.min.386bab8ebb751022ba05.js:1
e.run @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
(anonymous) @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
t.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
Ve.invokeTask @ web.min.386bab8ebb751022ba05.js:1
e.runTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
m @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
g @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
y @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
load (async)
R @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
t.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleEventTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
(anonymous) @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
i.set @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
send @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
ajax @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
S.each.S.<computed> @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
(anonymous) @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
c @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
fireWith @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
l @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
(anonymous) @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
x @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
t.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
Ve.invokeTask @ web.min.386bab8ebb751022ba05.js:1
e.runTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
g @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
y @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
load (async)
R @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
t.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleEventTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
(anonymous) @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
i.set @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
send @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
ajax @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
(anonymous) @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
c @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
fireWith @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
l @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
(anonymous) @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
x @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
t.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
Ve.invokeTask @ web.min.386bab8ebb751022ba05.js:1
e.runTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
g @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
y @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
load (async)
R @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
t.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleEventTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
(anonymous) @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
i.set @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
send @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
ajax @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
S.each.S.<computed> @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
getJSON @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
(anonymous) @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
c @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
fireWith @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
l @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
(anonymous) @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
x @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
t.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
Ve.invokeTask @ web.min.386bab8ebb751022ba05.js:1
e.runTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
g @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
y @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
load (async)
R @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
t.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.scheduleEventTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
(anonymous) @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
i.set @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
send @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
ajax @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
S.each.S.<computed> @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
i.reloadAdapter @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
(anonymous) @ powerbiportal.common.bundle.min.dec6934de4d55e7f019f.js:18
dispatch @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
v.handle @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:7
t.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
Ve.invokeTask @ web.min.386bab8ebb751022ba05.js:1
e.runTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
e.invokeTask @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
g @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
y @ powerbiportal.dependencies.externals.bundle.min.9334277c97a1912dee40.js:5
Show 35 more frames
Now I cleaned my browsers local storage and session storage with:
localStorage.clear();
sessionStorage.clear();
It increased the amount I'm able to save at once to 60_000. But when writing 50_000 and 9_000 it still fails with the same error (directly after that remove and write 60_000 is working).
My current assumption is, that only ~60kb are available for the custom visuals.
I solved my problem by reworking the access to external data by removing the dependency on using the PowerBI storage in the visual. This also enables me to store more data than 1mb.
The data I want to storage I now moved to a separate Azure Storage Blob and created a new SAS (Shared Access Signature) for accessing the blob. Next hurdle is that the fetch request is blocked by cors so we need to configure Allowed origins = null
, Allowed methods = GET
and Max age = 200
.
To the settings I added an option in the capabilities.json
, to let me configure a url which I can query.
"objects": {
"general": {
"displayName": "General settings",
"properties": {
"myurl": {
"displayName": "Url where data is stored.",
"type": { "text": true }
}
}
},
...
Then make sure the settings are displayed to the user for the custom visual by adding the following method to visual.ts
:
export class Visual implements IVisual {
// ...
// This is needed to ensure the settings are displayed on the Format-Tab
public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {
return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options);
}
When everything is configured we can use the fetch api in typescript to get the data and further process it.
private async GetData(): Promise<string> {
let url = this.settings.general.myurl;
if (url) {
try {
let resp = await fetch(url, {
referrer: "https://app.powerbi.com",
headers: {
// "Origin": "https://app.powerbi.com", // PowerBI sets this to null
}
});
let txt = await resp.text();
return Promise.resolve(txt);
} catch (err) {
return Promise.reject("Request failed.");
}
}
return Promise.reject("No url defined.");
}
For the write we just need to add the following to the cors configuration: Allowed origins = null
, Allowed methods = PUT
, Allowed headers=authorization,x-ms-blob-content-disposition,x-ms-blob-type,x-ms-date,x-ms-meta-m1,x-ms-meta-m2,x-ms-version
and Exposed headers = x-ms-blob*
.
Then we can use the REST API to upload the data.
private async SetData(data: string): Promise<void> {
let url = this.settings.general.saveurl; // URL with SAS token
if (url) {
try {
let resp = await fetch(url, {
referrer: "https://app.powerbi.com",
headers: {
// "Origin": "https://app.powerbi.com", // PowerBI sets this to null
"x-ms-version": "2017-11-09",
"x-ms-date": new Date().toISOString().split('T')[0],
"Content-Type": "text/plain; charset=UTF-8",
"x-ms-blob-content-disposition": "attachment; filename=\"mydata.txt\"",
"x-ms-blob-type": "BlockBlob",
"x-ms-meta-m1": "v1",
"x-ms-meta-m2": "v2",
// "Authorization": "SharedKey myaccount:..." // not needed with sas token
},
method: "PUT",
body: data
});
return Promise.resolve();
} catch (err) {
return Promise.reject("Request failed.");
}
}
return Promise.reject("No save url defined.");
}