如何在 Power Bi 中存储自定义视觉对象的数据

How to store data in Powerbi for custom visual

对于我的 PowerBI 自定义视觉对象,我想在存储器中存储一些数据。根据 documentation 最多支持 1Mb。 它仅适用于 3_000 个零,但 30_000 个零因未定义错误而失败。 我使用 Developer Visual 显示我的自定义视觉对象以进行调试。

我尝试存储数据然后通过以下方式读取数据(在可视化更新中):

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
        });
//...
}

保存 30_000 字符时出现“未定义”错误:

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

更新

现在我清理了我的浏览器本地存储和会话存储:

localStorage.clear();
sessionStorage.clear();

它使我一次可以节省的金额增加到 60_000。但是当写入 50_000 和 9_000 时它仍然失败并出现相同的错误(直接在删除和写入 60_000 之后)。

我目前的假设是,只有约 60kb 可用于自定义视觉效果。

信息

我通过消除对在视觉对象中使用 PowerBI 存储的依赖来重新访问外部数据,从而解决了我的问题。 这也使我能够存储超过 1mb 的数据。

我的解决方法

我想要存储的数据我现在移动到一个单独的 Azure 存储 Blob 并创建了一个新的 SAS(共享访问签名)来访问该 blob。下一个障碍是获取请求被 cors 阻止,所以我们需要配置 Allowed origins = nullAllowed methods = GETMax age = 200.

我在 capabilities.json 中添加了一个选项,让我配置一个 url 我可以查询。

"objects":   {
        "general": {
            "displayName": "General settings",
            "properties": {
                "myurl": {
                    "displayName": "Url where data is stored.",
                    "type": { "text": true }
                }
            }
        },
...

然后通过将以下方法添加到 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);
    }

当一切都配置好后,我们可以在 typescript 中使用 fetch api 来获取数据并进一步处理它。

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.");
}

对于写入,我们只需将以下内容添加到 cors 配置中:Allowed origins = nullAllowed methods = PUTAllowed headers=authorization,x-ms-blob-content-disposition,x-ms-blob-type,x-ms-date,x-ms-meta-m1,x-ms-meta-m2,x-ms-versionExposed headers = x-ms-blob*。 然后我们可以使用REST API上传数据。

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.");
    }