Passing report level filter to power bi from asp.net mvc application - asp.net-mvc

I have embedded power bi report in my asp.net mvc application. It is working fine and it is showing data. I am having one issue, in my application every client has few branches like cities. Every user for that client may have access to all or some branches and based on that access we show data when that user is logged into system.
I want to achieve same in power bi that when user is logged into system and view reports it should show him/her data of branch he/she has access to. I found one solution
[Can I pass a dynamic query parameter to an embedded Power BI report in ASP.Net MVC? where we can set filter values from program side. I applied this in my view but i am still getting all data.
const branchFilter = {
$schema: "http://powerbi.com/product/schema#basic",
target: {
table: "tblWorkhistory",
column: "BranchID"
},
operator: "In",
values: [1],
filterType: models.FilterType.BasicFilter
}
var config = {
type: 'report',
tokenType: models.TokenType.Embed,
accessToken: accessToken,
embedUrl: embedUrl,
id: embedReportId,
permissions: models.Permissions.All,
viewMode: models.ViewMode.View,
filters: [branchFilter],
settings: {
filterPaneEnabled: true,
navContentPaneEnabled: true
}
};
Here i want to apply filter where it will show data for only branch whose id is 1 but it is showing all data. Am i missing anything here? do i need to do anything report side also after this code?
Regards,
Savan

Applying filter using embed config is supported, and the code sample you've shared seems valid.
If report.setFilters fails as well, seems like something with the filter is wrong.
Try to verify the data type of the filter, should it be 1 or "1"?
If this doesn't work, is there any error message being returned from .setFilters request?:
const filter = { ... };
report.setFilters([filter])
.catch(errors => {
// Handle error
});
Learn more here about setting filters through JS SDK.

To show data based on the user logged into you application you have to apply Row Level Security (RLS) in your power bi report first and then follow the steps from following article https://learn.microsoft.com/en-us/power-bi/developer/embedded-row-level-security

Related

$batch request resulting in error "Default changeset implementation allows only one operation"

I am making a worklist application using SAPUI5. The problem is that when I create an entry and then create another one right after that, I get the following error:
Default changeset implementation allows only one operation.
I checked the $batch header and I see that there is a MERGE and a POST, with the MERGE updating the previous entry for some reason. Can anyone shed some light? Could it be a backend error and not a UI5 error?
Creating the new entry:
_onMetadataLoaded: function() {
var oModel = this.getView().getModel();
var that = this;
// ...
oModel.read("/USERS_SET", {
success: function(oData) {
var oProperties = {
Qmnum: "0",
Otherstuff: "cool"
};
that._oContext = that._oView.getModel().createEntry("/ENTITYSET", {
properties: oProperties
});
that.getView().setBindingContext(that._oContext);
// ...
}
});
},
handleSavePress: function(oEvent) {
// ...
this.getView().getModel().submitChanges({
success: function(oData) {
// ...
},
error: function(oError) {
// ...
}
});
},
tl-dr: Apparently you must be using the SAP Gateway. If you do not need to process those requests in one transaction then send them in different changesets. If you do not need batch calls at all consider turning it off by supplying your model with "useBatch": false upon instantiation. However if you need to process the requests together in one transaction then you have to read the details below.
In order to understand the problem you have to understand how the gateway and the batch and changeset requests work.
Batch requests consist of multiple requests bundled together. The purpose is to open only one connection and group together relevant requests so that the overhead is minimalized. Changesets form smaller blocks inside batch requests, where modification requests can be bundled and processed together in order to ensure an all-or-nothing characteristic.
So on the gateway side: there are two relevant classes for your OData service, assuming that you have used the SAP Gateway Service Builder (SEGW transaction). There is one with the ending ...DPC and one with ...DPC_EXT. Don't touch the former, it will be always regenerated when you update your service in the service builder. The latter is the one that we will need in this example. You will have to redefine at least two methods:
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_PROCESS
By default the changeset_begin method will only allow changeset processing for changesets where the number of requests equals to one. This can be handled automatically that's why a limitation exists. If there were more requests one could not ensure their processing automatically as they could have a business dependency on each other.
So make sure to allow a bundled (deferred mode) processing of changesets under the desired conditions:
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN: first call the super->/iwbep/if_mgw_appl_srv_runtime~changeset_begin method in a try catch block, then loop at it_operation_info to decide and narrow down processing only in selected cases and then allow cv_defer_mode only for the selected cases, otherwise throw a /iwbep/cx_mgw_tech_exception=>changeset_not_supported exception.
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_PROCESS: all requests will be available in the it_changeset_request. Make sure to fill the ct_changeset_response table with the responses.
METHOD /iwbep/if_mgw_appl_srv_runtime~changeset_process.
DATA:
lv_operation_counter TYPE i VALUE 0,
lr_context TYPE REF TO /iwbep/cl_mgw_request,
lr_entry_provider TYPE REF TO /iwbep/if_mgw_entry_provider,
lr_message_container TYPE REF TO /iwbep/if_message_container,
lr_entity_data TYPE REF TO data,
ls_context_details TYPE /iwbep/if_mgw_core_srv_runtime=>ty_s_mgw_request_context,
ls_changeset_response LIKE LINE OF ct_changeset_response.
FIELD-SYMBOLS:
<fs_ls_changeset_request> LIKE LINE OF it_changeset_request.
LOOP AT it_changeset_request ASSIGNING <fs_ls_changeset_request>.
lr_context ?= <fs_ls_changeset_request>-request_context.
lr_entry_provider = <fs_ls_changeset_request>-entry_provider.
lr_message_container = <fs_ls_changeset_request>-msg_container.
ls_context_details = lr_context->get_request_details( ).
CASE ls_context_details-target_entity.
WHEN 'SomeEntity'.
"Do the processing here
WHEN OTHERS.
ENDCASE.
ENDLOOP.
ENDMETHOD.
From the error I can tell you must be using SAP GW :-) This happens only for batch requests containing more than one create/delete/update calls and it's related to transaction security ("all or nothing"). What you have to do is redefining the corresponding GW method, I think it was CHANGESET_BEGIN. See https://archive.sap.com/discussions/thread/3562720 for some details (can't offer more for now...).

Get Data from Odata service with Logged in User

I have one Odata service , which is providing me the data and I am able to display this data on table. We are going to deploy this application to Launchpad. Now we have this requirement in which logged in user must get the data according to his/her login ID. So If my user ID is XXXXX , I should get the records only for XXXXX. I am unable to understand the process flow. Shall we implement the logic in Odata itself or should I get all the data and filter the model on UI, before displaying it.
Regards,
MS
In oData itself you can access login user by sy-uname. using that user you can filter your data.
OR
In front end you can access login user by below code
var vUrl = "proxy/sap/bc/ui2/start_up";
var oxmlHttp = null;
oxmlHttp = new XMLHttpRequest();
oxmlHttp.onreadystatechange = function() {
if (oxmlHttp.readyState == 4 && oxmlHttp.status == 200) {
var oUserData = JSON.parse(oxmlHttp.responseText);
vUser = oUserData.id;
}
};
oxmlHttp.open( "GET", vUrl, false );
oxmlHttp.send(null);
You have to handle this in Odata only. Get User id from UI using
var storename = sap.ushell.Container.getService("UserInfo").getId();
and set it to Odata to filter and send back the results.
You should handle such requirements in the Service level (OData level), not in the UI.
In DPC_EXT class variable SY-UNAME gives you the logged in user. So you should filter your records by deriving more information from that.

persist bot chat data in bot framework wrt to Form Flow

I want to know whether is there any feature in bot framework to get the user and bot chat completely. I have gone through the official documentation, but the way I understood it is that, only to that context we can save the chat data. If at all we have to store the whole data, we have to take care of it.
I tried using this,
StateClient sc = activity.GetStateClient();
BotData userData1 =
sc.BotState.GetConversationData(activity.ChannelId, activity.Conversation.Id);
userData1.Data = userData1.Data + activity.Text;
sc.BotState.SetConversationData(activity.ChannelId, activity.Conversation.Id, userData1);
This does persist the user data, but I am stuck with how to persist it in the form flow.
I am not sure how to persist data of bot and user wrt to Form Flow using SetConversationData. I even need the bot to persist the prompt message of the form flow. So that I ll have the complete conversation b/w user and the bot.
This tutorial may help:
Introduction To FormFlow With The Microsoft Bot Framework
The data from the user is automatically persisted during the FormFlow.
When the FormFlow is completed you can persist it like this:
public static IForm<ProfileForm> BuildForm()
{
return new FormBuilder<ProfileForm>()
.Message("Welcome to the profile bot!")
.OnCompletion(async (context, profileForm) =>
{
// Set BotUserData
context.PrivateConversationData.SetValue<bool>(
"ProfileComplete", true);
context.PrivateConversationData.SetValue<string>(
"FirstName", profileForm.FirstName);
context.PrivateConversationData.SetValue<string>(
"LastName", profileForm.LastName);
context.PrivateConversationData.SetValue<string>(
"Gender", profileForm.Gender.ToString());
// Tell the user that the form is complete
await context.PostAsync("Your profile is complete.");
})
.Build();
}

Search with Relay doesn't include new results due to local cache

I've implemented a search-as-you-type component in React and Relay. It's roughly the same setup as search functionality using relay
It works as intended with one exception. New results from the server never appear when I retype a search I've already performed on the client. I looks like Relay always goes to the local cache in this case.
So, for example, say I've searched for 'foo' and didn't find any results. Now, seconds later, another user on the website creates this 'foo', but Relay will never query the server since the cached response to the 'foo' search was an empty result.
Is there a pattern or best practice for this scenario?
The query is as follows. I call this.props.relay.setVariables to perform the search:
initialVariables: {
search: '',
hasSearch: false
},
fragments: {
me: () => Relay.QL`
fragment on Viewer {
relationSearch(search: $search) #include(if: $hasSearch) {
... on User {
username
}
}
}
`
}
The answer seems to be to use this.props.relay.forceFetch with the search variables instead.
See https://facebook.github.io/relay/docs/api-reference-relay-container.html#forcefetch
Someone correct me if this isn't best practice.

Facebook UI call in ASP.NET MVC does not return the picture it should

Does anyone know why the picture attribute is not working in following Facebook UI call?
function postToWallUsingFBUi()
{
var data=
{
method: 'stream.publish',
message: "Posted using FB.ui and picture.",
display: 'iframe',
caption: "Caption",
name: "Name",
//ver 1 picture: 'http://www.somedomain.com/albums/s339/rockaja/fb-520.png',
//ver 2 picture: '#Url.Action("Action", "Controller", new { PageId = Model.PageTabId }, Request.Url.Scheme)',
picture: 'https://localhost/MyVirtualDirectory/Controller/Action/283659015078395',
link: "http://www.mydomain.com/", // Go here if user click the picture
description: "Description field",
actions: [{ name: 'action_links text!', link: 'http://www.mydomain.com' }]
}
FB.ui(data, onPostToWallCompleted);
}
As you can see the picture attribute uses a picture from localhost. If i paste this URL into the browsers's Address field, i get the picture as expected.
I also commented out other two versions:
version 1 is working properly as expected, but
version 2 is not working (this is an ASP.NET MVC call, but that fact does not affect the result).
May be it is due to the fact that i request a localhost-ed picture?!
I have never worked on FB API so take my suggestion with a pinch of salt.
Based on my understanding of how Facebook works, whatever pictures you share on user's wall go into FB's data store first and are always pulled from that store.
Here, The Facebook API may be downloading the picture from the URL you have provided and push it into it's own store before publishing it on user's walls. When you use a localhost url, then the call to download the picture would obviously fail.
There must be another version of the API where you should be able to send the picture content as byte array. If there is, then you can load the picture from disk yourself and send the byte array in the API

Resources