I am trying to embed a Power BI report to a custom asp.net application. I have followed Microsoft's developer guidance, but I am hitting some odd issues that are not documented very well on the web.
Here is my current code:
using System;
using System.Configuration;
using System.Threading.Tasks;
using Microsoft.Rest;
using Microsoft.PowerBI.Api;
using Microsoft.PowerBI.Api.Models;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Collections.Generic;
using Microsoft.Identity;
using System.Web;
using System.Security.Cryptography.X509Certificates;
namespace AppOnlyAuthPBI.Models
{
public class PBIEmbeddedManager
{
private static string resourceUriPowerBi = "https://analysis.windows.net/powerbi/api";
private static string urlPowerBiRestApiRoot = "https://api.powerbi.com/";
const string aadRootAuthorizationEndpoint = "https://login.windows.net/";
static readonly string tenantId = ConfigurationManager.AppSettings["tenant-id"];
static readonly string aadTenantAuthorizationEndpoint = aadRootAuthorizationEndpoint +
tenantId + "/";
private static string applicationId = ConfigurationManager.AppSettings["application-id"];
private static string applicationSecret = ConfigurationManager.AppSettings["application-secret"];
private static string workspaceId = ConfigurationManager.AppSettings["app-workspace-id"];
private static string reportId = ConfigurationManager.AppSettings["report-id"];
static string GetAccessToken()
{
var authContext = new AuthenticationContext(aadTenantAuthorizationEndpoint);
var clientCredential = new ClientCredential(applicationId, applicationSecret);
return authContext.AcquireTokenAsync(resourceUriPowerBi, clientCredential).Result.AccessToken;
}
private static PowerBIClient GetPowerBiClient()
{
var tokenCredentials = new TokenCredentials(GetAccessToken(), "Bearer");
return new PowerBIClient(new Uri(urlPowerBiRestApiRoot), tokenCredentials);
}
public static async Task<ReportEmbeddingData> GetReportEmbeddingData()
{
PowerBIClient pbiClient = GetPowerBiClient();
var report = await pbiClient.Reports.GetReportInGroupAsync(workspaceId, reportId);
var embedUrl = report.EmbedUrl;
var reportName = report.Name;
GenerateTokenRequest generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
string embedToken =
(await pbiClient.Reports.GenerateTokenInGroupAsync(workspaceId,
report.Id,
generateTokenRequestParameters)).Token;
return new ReportEmbeddingData
{
reportId = reportId,
reportName = reportName,
embedUrl = embedUrl,
accessToken = embedToken
};
}
}
}
I am having issues ReportEmbeddingData() method.
var report = await pbiClient.Reports.GetReportInGroupAsync(workspaceId, reportId);
Here I am getting two errors, both stating cannot convert string to System.Guid. So I tried to parse them like so...
Guid.Parse(workspaceId)
Guid.Parse(reportId)
But, doing this then causes another error to appear which has no information surrounding it on the web...
string embedToken =
(await pbiClient.Reports.GenerateTokenInGroupAsync(workspaceId,
report.Id,
generateTokenRequestParameters)).Token;
I get an error on Reports.GenerateTokenInGroupAsync saying the following: "CS1929 - 'IReportsOperations' does not contain a definition for for 'GenerateTokenInGroupAsync' and the best extension method overload 'IDashboardOperationExtensions, guid, guid, GenerateTokenPermissions, CancellationToken' requires a receiver type of 'IDashboardsOperation'
To me it seems like I am missing a nuGet package, but I have verified this and everything is working as intended there and I have the required using statements applied as well.
Has anyone encountered this or does anyone know how to correct this? It seems really odd to me that Microsoft is recommending this code and I am hitting an error, leading me to believe that I am the one making the mistake but it is alluding me.
Thank you~
Use GenerateTokenInGroupWithHttpMessagesAsync()
Related
I want to get the domain name and only the domain name without the TLD
Before: example.com After: example
I tried using the package domainname-parser but this did not work because my operation is being threaded and I get the error: The process cannot access the file 'PATH' because it is being used by another process.' Here:
var domaininfo = new DomainParser(new WebTldRuleProvider()).Parse(uri.Host);
it's easiest way to use Uri class, but it's not memory efficient.
you should use Span and implement it by yourself if you want memory efficient version.
using System;
public class HelloWorld
{
public static void Main(string[] args)
{
// you can use Uri class,
var url = "https://www.youtube.com/watch?v=kgTeT3AIM4g";
var uri = new Uri(url);
Console.WriteLine(uri.Host); // www.youtube.com
}
}
Hey man you could try this code:
public static void Main(string[] args)
{
string urlString = "http://example.site.com/index.html";
Console.WriteLine(GetDomainNameOfUrlString(urlString));
}
private static string GetDomainNameOfUrlString(string urlString)
{
var host = new Uri(urlString).Host;
return host.Substring(host.LastIndexOf('.', host.LastIndexOf('.') - 1) + 1);
}
This is my first try to program a Xslt2.0 transformation with SaxonHE 9.9 in C#, so the problem here is when I create the serilizer I get the error that the class Saxon.Api.Serializer contains no constractor with 0 arguments.
I know what this error means, but not why it occurs, cause each example that I see creates the serializer like this.. This question sounds a bit stupid, but I cannot find a answer to get it work.
using Saxon.Api;
namespace XY
{
class Program
{
static void Main(string[] args)
{
String SourceFilename = "./test/test.xml";
String StylesheetFilename = "./scripte/xml-to-html.xsl";
String OutputFilename = "./Output/test.html";
using (FileStream streamXml = File.OpenRead(SourceFilename))
{
using (FileStream streamXsl = File.OpenRead(StylesheetFilename))
{
Processor processor = new Processor();
DocumentBuilder builder = processor.NewDocumentBuilder();
Uri uri = new Uri("urn:test");
builder.BaseUri = uri;
XdmNode input = builder.Build(streamXml);
XsltTransformer transformer = processor.NewXsltCompiler().Compile(streamXsl).Load();
transformer.InitialContextNode = input;
Serializer serializer = new Serializer();
serializer.SetOutputFile(OutputFilename);
transformer.Run(serializer);
}
}
Console.WriteLine("test.html created successfully");
}
}
}
EDIT
using System;
using Saxon.Api;
using System.IO;
using System.Reflection;
namespace XY
{
class Program
{
static void Main(string[] args)
{
string currentDirectory = Directory.GetCurrentDirectory();
String SourceFilename = ".\\test\\test.xml";
String StylesheetFilename = ".\\scripte\\xml-to-html.xsl";
String OutputFilename = ".\\Output\\result.html";
if (StylesheetFilename.StartsWith(".\\"))
{
StylesheetFilename = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + StylesheetFilename;
}
if (SourceFilename.StartsWith(".\\"))
{
SourceFilename = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + SourceFilename;
}
var uri_source = new System.Uri(SourceFilename);
var uri_xsl = new System.Uri(StylesheetFilename);
Processor processor = new Processor();
XdmNode input = processor.NewDocumentBuilder().Build(uri_source);
processor.SetProperty("http://saxon.sf.net/feature/preferJaxpParser", "true");
XsltCompiler compiler = processor.NewXsltCompiler();
XsltExecutable executable = compiler.Compile(uri_xsl);
XsltTransformer transformer = executable.Load();
transformer.InitialContextNode = input;
Serializer serializer = processor.NewSerializer();
System.IO.StreamWriter stream = new StreamWriter(OutputFilename);
serializer.SetOutputWriter(stream);
transformer.Run(serializer);
stream.Close();
}
}
}
I change also some other thinks and now it works, thanks for the answers.
I'll log a bug on the fact that there are sample apps and/or documentation that use the "new Serializer()" form.
We dropped this from the Java product in 9.8 because it caused constant trouble that the Serializer doesn't (necessarily) have access to all the configuration options (held in the Processor); also using a factory method Processor.newSerializer() potentially allows us to to create a subclass of Serializer, so it's more flexible. We then followed this pattern on .NET in the 9.9 release, partly for the same reasons, and partly because the .NET API has now been rewritten as a very thin layer on top of the Java API, which helps us to maintain commonality, and simplifies testing.
We try hard to maintain backwards compatibility in the main product APIs but it's not a requirement that overrides all others; if we feel that we got something badly wrong, then we fix it. As some people say to justify the policy, "the future is longer than the past".
LATER
We have done some checking and we think the 9.9 documentation and sample applications are correct; you must be using an older version. If I'm wrong, please identify the specific location where you found incorrect information.
In 9.9 you can (or really need to) create a Serializer with the various overloads of processor.NewSerializer (see http://saxonica.com/html/documentation/dotnetdoc/Saxon/Api/Processor.html#NewSerializer(Stream))..
Here is my solution for the problem:
using System;
using System.IO;
using Saxon.Api;
namespace Project1
{
public static class ClassMain
{
public static string TransformXml(string xmlData, string xslData)
{
var xsltProcessor = new Processor();
var documentBuilder = xsltProcessor.NewDocumentBuilder();
documentBuilder.BaseUri = new Uri("file://");
var xdmNode = documentBuilder.Build(new StringReader(xmlData));
var xsltCompiler = xsltProcessor.NewXsltCompiler();
var xsltExecutable = xsltCompiler.Compile(new StringReader(xslData));
var xsltTransformer = xsltExecutable.Load();
xsltTransformer.InitialContextNode = xdmNode;
var results = new XdmDestination();
xsltTransformer.Run(results);
return results.XdmNode.OuterXml;
}
public static void Main()
{
var xmlData = File.ReadAllText("a.xml");
var xslData = File.ReadAllText("a.xsl");
var data = TransformXml(xmlData, xslData);
Console.WriteLine(data);
Console.ReadKey();
}
}
}
I try to log in to the site using the AngleSharp library.
I use code for this.
class Program
{
const string sourceToSite = "https://mail.ru/";
const string sourceToTarget = "https://e.mail.ru/messages/inbox/";
static async void QueryToOrders()
{
var config = Configuration.Default.WithDefaultLoader().WithCookies();
var context = BrowsingContext.New(config);
await context.OpenAsync(sourceToSite);
var check = context.Active.QuerySelector<IHtmlFormElement>("form#Auth").SubmitAsync(new { Login = EMAIL + "#mail.ru", Password = PASSWORD }).Result;
var msgs = await context.OpenAsync(sourceToTarget);
}
}
I get an error:
"The error "Non-generic method" IParentNode.QuerySelector (string) "cannot be used with type arguments."
Question
How to fix the error?
I believe that the form of QuerySelector that takes a generic argument is an extension method. You need to add a using for the namespace it lives in:
using AngleSharp.Extensions;
With the 0.11 version there is no more AngleSharp.Extensions you need:
using AngleSharp;
using AngleSharp.Dom;
using AngleSharp.Html.Dom;
See sample here
I am writing a c# mechanism to upload a file to a Rails server, using Json.
Before getting to the file part, i am just trying to post to the server, and seem to be having some problems with the json string that is arriving at the server..
What might I be doing wrong ? I already tried two different ways of serializing the string, and even loading an already serialized string...
I wonder if it has anything to do with the double quotes both at beginning and end of the string apparently being sent to server, and how to remove them from the request (without the surrounding quotes and using RestClient from WizTools.org, it all goes fine...) :
MultiJson::DecodeError (757: unexpected token at '"{\"receipt\":{\"total\":100.0,\"tag_number\":\"xxxxx\",\"ispaperduplicate\":true},\"machine\":{\"serial_number\":\"111111\",\"safe_token\":\"1Y321a\"}}"')
My c# code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RestSharp;
using System.Web.Script.Serialization;
using Newtonsoft.Json;
namespace RonRestClient
{
class templateRequest
{
public Receipt receipt;
public class Receipt
{
public float total;
public String tag_number;
public bool ispaperduplicate = true;
public Receipt(float total, String tagnr)
{
this.total = total;
this.tag_number = tagnr;
}
};
public Machine machine;
public class Machine
{
public String serial_number;
public String safe_token;
public Machine(String machinenr, String safe_token)
{
this.serial_number = machinenr;
this.safe_token = safe_token;
}
};
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string path = #"C:\file.pdf";
string tagnr = "p94tt7w";
string machinenr = "2803433";
string safe_token = "123";
float total = 100;
templateRequest req = new templateRequest();
req.receipt = new templateRequest.Receipt(total, tagnr);
req.machine = new templateRequest.Machine(machinenr, safe_token);
//string json_body = JsonConvert.SerializeObject(req);
//string json_body = new JavaScriptSerializer().Serialize(req);
string json_body = #"{""receipt"" : {""total"":"+total+#", ""tag_number"":"""+tagnr+#""",""ispaperduplicate"":true},""machine"":{""serial_number"": """+machinenr+#""", ""safe_token"": """+safe_token+#"""}}";
var client = new RestClient("http://localhost:3000");
var request = new RestRequest("/receipts",Method.POST);
//set request Body
request.AddHeader("Content-type", "application/json");
request.AddHeader("Accept", "application/json");
request.RequestFormat = DataFormat.Json;
request.AddBody(json_body);
//request.AddParameter("text/json", json_body, ParameterType.RequestBody);
// easily add HTTP Headers
// add files to upload (works with compatible verbs)
//request.AddFile("receipt/receipt_file",path);
// execute the request
IRestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
if(response.ErrorMessage !="") content += response.ErrorMessage;
response_box.Text = content;
}
}
}
The problem is that the RestRequest.AddBody (source code) method actually presupposes that the content is not serialized to the correct format.
Meaning that it thinks that you are trying to pass the .NET string as a JSON string, instead of recognizing that you actually want to pass that string as a JSON object.
However, that means that you are actually doing too much work, by serializing the object to JSON yourself:
Replace line
request.AddBody(json_body);
with:
request.AddBody(req);
You can control the way that the serialization to JSON is done with the RestRequest.JsonSerializer property.
If you absolutely want to hold a JSON string, then I guess you might want to write:
request.AddParameter("application/json", json_body, ParameterType.RequestBody);
(I see that you have a line which is commented that practically does that - why did you comment it?)
I'm trying to use the eBay Finding API to send an advanced search request and return the results. I have included my code below.
For some reason when I get to the following line:
FindItemsAdvancedResponse response = service.findItemsAdvanced(request);
the object called "response" is coming back as null.
I'm not sure where I'm going wrong and no exception is being thrown from the call to service.findItemsAdvanced()
If you could take a look and offer any advice at all I would be most grateful.
Here is my program.cs up until the problem
Progam.cs
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using EbayParser.com.ebay.developer;
using System.Net;
namespace EbayParser
{
class Program
{
static void Main(string[] args)
{
try
{
// Creating an object to the BestMatchService class
CustomFindingService service = new CustomFindingService();
service.Url = "http://svcs.sandbox.ebay.com/services/search/FindingService/v1";
com.ebay.developer.FindItemsAdvancedRequest request = new EbayParser.com.ebay.developer.FindItemsAdvancedRequest();
//Create Filter Objects
com.ebay.developer.ItemFilter filterEndTimeFrom = new EbayParser.com.ebay.developer.ItemFilter();
com.ebay.developer.ItemFilter filterEndTimeTo = new EbayParser.com.ebay.developer.ItemFilter();
com.ebay.developer.ItemFilter filterCatID = new EbayParser.com.ebay.developer.ItemFilter();
//Set Values for each filter
filterEndTimeFrom.name = EbayParser.com.ebay.developer.ItemFilterType.EndTimeFrom;
filterEndTimeFrom.value = new string[] { "" };
filterEndTimeTo.name = EbayParser.com.ebay.developer.ItemFilterType.EndTimeTo;
filterEndTimeTo.value = new string[] { "" };
filterCatID.name = EbayParser.com.ebay.developer.ItemFilterType.EndTimeFrom;
filterCatID.value = new string[] { "" };
//Create the filter array
com.ebay.developer.ItemFilter[] itemFilters = new EbayParser.com.ebay.developer.ItemFilter[3];
//Add Filters to the array
itemFilters[0] = filterCatID;
itemFilters[1] = filterEndTimeFrom;
itemFilters[2] = filterEndTimeTo;
request.itemFilter = itemFilters;
request.keywords = "ipod";
// Creating response object
FindItemsAdvancedResponse response = service.findItemsAdvanced(request);
and here is the code for the class called "CustomFindingService.cs"
CustomFindingService.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using EbayParser.com.ebay.developer;
namespace EbayParser
{
class CustomFindingService : FindingService
{
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
try
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(uri);
request.Headers.Add("X-EBAY-SOA-SECURITY-APPNAME", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
request.Headers.Add("X-EBAY-SOA-OPERATION-NAME", "findItemsByKeywords");
request.Headers.Add("X-EBAY-SOA-SERVICE-NAME", "FindingService");
request.Headers.Add("X-EBAY-SOA-MESSAGE-PROTOCOL", "SOAP11");
request.Headers.Add("X-EBAY-SOA-SERVICE-VERSION", "1.0.0");
request.Headers.Add("X-EBAY-SOA-GLOBAL-ID", "EBAY-US");
return request;
}
catch (Exception ex)
{
throw ex;
}
}
}
}
I had exactly the same problem when I went from finding by keywords to using the advanced method. I spent a while scratching my head myself but it turned out to have a simple fix:
Your header X-EBAY-SOA-OPERATION-NAME reads findItemsByKeywords. Changing it to findItemsAdvanced should do the trick.
If you leave any of the filters blank in the filter array you will get the SOA Operation Header missing exception whether or not you have included the headers correctly.
You should check the filters are not null before applying them to your request.