Power BI Embedded PostImportWithFile returning BadRequest - c#

I'm looking to post a PBIX file up to a workspace through the .NET API using the PostImportWithFile method of the PowerBiClients Imports object. The code is pretty much identical to that seen in option 6 of the Provision Sample (see https://github.com/Azure-Samples/power-bi-embedded-integrate-report-into-web-app/blob/master/ProvisionSample/Program.cs).
There is a workspace collection and a workspace that have been created. The workspace was created through code using the relevant API methods so I know that the authentication side of things is working correctly.
When I call the PostImportWithFile method I'm getting a BadRequest exception being thrown. To verify that this wasn't something to do with my code I've compiled and run the ProvisionSample and selected option 6 and selected the same file and received the same result.
I'm supplying null for the dataset parameter, which is optional and defaults to null anyway, so I can't see this being the cause of my issues.
I've been unable to find anything online regarding this method and a BadRequest so was wondering if there was anyone with experience with this API that had run into something similar?
The PBIX file works fine through Power BI Services, so I'm assuming nothing is wrong with the file.

Based on the documentation here it looks like you would need to supply a datasetname, it does not look like it is optional.
public static Task<Import> PostImportWithFileAsync(
this IImports operations,
string collectionName,
string workspaceId,
Stream fileStream,
string datasetDisplayName,
Nullable<int> nameConflict = null,
CancellationToken cancellationToken = null)
Non async version here also looks like datasetdisplayname is not optional.
Hope this helps.

Related

Is Request.Cookies["value"] in c# controller some static reference

I am having difficulty to understand some code from GitHub (I am learning angular, however this is server side code written in c#)
The code is available on GitHub code).
I can't completely understand the very first line of code var refreshToken = Request.Cookies["refreshToken"]; Where does Request.Cookies come from? It is not a variable and it looks like a static call to some array Cookies. How does the element of that array happen to contain "refresh-token" item?
Could someone please explain this? (this code comes from the class derived from BaseController)
[HttpPost("refresh-token")]
public ActionResult<AuthenticateResponse> RefreshToken()
{
var refreshToken = Request.Cookies["refreshToken"];
var response = _accountService.RefreshToken(refreshToken, ipAddress());
setTokenCookie(response.RefreshToken);
return Ok(response);
}
When you work in an HTTP application, .NET manages some context for you. A bunch of stuff you write, like your POST action, is provided with an HTTP context, which has properties that provide information about the request. This includes headers, cookies, etc.
When you use Request within an MVC controller (or some other HTTP context) you'll get access to the HttpContext and Request that relates to the specific single request. It feels like magic, but it's the framework doing the work for you.
A bit more information on context.
You need to check other serverside codes which set the cookie,Cookie is created in serverside firstly and sent to User Agent,often stored in your browser.next time you send a request,your request may contain the cookie
you could check the codes like:Response.Cookies.Append(....)

ASP.NET and C#: where do you store the rest client url?

I have my rest client url hard-coded in my code-behind, but upon peer-reviewing my code, I was asked to move that url to the config file so that it can be changed for each environment.
Visual Studio 2019 now complains because my rest client url has an invalid = sign as token in the url itself, and it expects ; as token instead.
Has anyone ever come across this, and is it correct to move the rest client to the config file? In theory that should not change.
Can't share the full url, but the part that is highlighted as error is this: version=2.0&details=true.
I found the answer. The problem is in the & symbol itself. Once converted to &, the errors Visual Studio was highlighting were gone and my solution worked again.
If i will do that i will save in config file only base url like this
"WebConfig": {
"SmsCenterApi": "https://some_site.com/SendService"
}
and in code I can complete the link
string url = WebConficData.SmsCenterApi+"version=2.0&details=true";
andafter that I can use url to make some request. For multi-environments web.config and appsettings is avesome. You just change base url for each env and that's it.
I think the answer to your questions
where do you store the rest client url?
is it correct to move the rest url to the config file?
is dependent on how you implement the rest request to that url. As you do not show any information on how you implement the rest call, I would like to show you one possible way and hopefully give you an impression about which things you should consider when implementing a solution.
So we can basically (for the sake of completeness) split an rest-endpoint url into two parts which might affect our implementation.
The base url:
"https://www.some-nice-name.com/SomeEndPoint"
and the parameters
?key1=value1&key2=value2
having this in mind, you could go the way and split them up, storing the base url and the parameters in two different nodes/attributes in a config file:
{
"BaseUrl" : "https://www.some-nice-name.com/SomeEndPoint",
"UrlParams" : "?key1=value1&key2=value2"
}
Or in one node/attribute, or even split each single parameter pair ("key1=value1") into own fields. And so on, and so on......
Anyway, if we now jump into our C# code and implement the Rest call, we have a wide range of different possible solution. For this example I will show you how to use the RestSharp NuGet package and why it might influences our decision on the above question.
So one basic example:
// I will not show the implementation of ReadYourConfigStuff() because its fairly clear what should happen here
var config = ReadYourConfigStuff();
// Give the BaseUrl to our REST client
var restClient = new RestClient(config.BaseUrl);
// Just taking GET as we have some GET Parameters
var restRequest = new RestRequest(Method.GET);
so far so good. But we still miss our parameters right?
Let's go ahead:
// RestSharp gives us a very nice tool to add GET parameters to our request
restRequest.AddParameter("key1", "value1");
restRequest.AddParameter("key2", "value2");
That looks quite different to what we added to our config file, does it? Yes it does. As RestSharp gives us a tool at hand which allows to add parameters one by one, we are free to choose how to store and maintain those in our code. And if we have a look on the AddParameter defintion
public IRestRequest AddParameter(string name, object value);
we see that the second parameter can be any object. Amazing!
So my answer to your question is: Yes you can store it in the config file, but does it fit to your implementation? Are the parameters fix or do they change? How does your favorite tooling would like you to implement the rest request?
Based on the answers to these questions, I would take a decision rather to use a config file or not.

C# HttpRequestMessage.GetCorrelationId method returns duplicates

My team and I have been working on this issue for a couple of days and we can't determine the root cause why GetCorrelationId() returns duplicates GUID sometimes.
Within the application that I'm working right now we use the correlation id to tie up the request path.
For example the UI sends a Save request to the API in .NET. When the API calls the save method in the query service from the controller, it pass through the result of Request.GetCorrelationId() to the method call.
The save method in the query service uses this parameter to insert a new row in the audit_logs table with the request information.
The save method then calls other save methods on nested objects that belongs to the main Object, passing the correlation_id generated in the controller.
Something like this
[ Controller ]
var correlation_id = HttpRequestMessage.GetCorrelationId();
{
ParentObject.save(correlation_id) -> {
ChildObject1.save(correlation_id),
ChildObject2.save(correlation_id),
}
}
My question is. Is this an issue of how GetCorrelationId creates the GUID object or there is something wrong with the configuration of the framework?
The framework is .NET Framework 4.6.1
We see this issue in IIS Express and IIS server
I can't share code but I'll do my best to share as much information is needed to troubleshoot this issue.
This are some examples of duplicates GUID
Thanks
OK I found a solution. I'm posting it so if someone else has the same issue can get this example.
After some more digging on Google I found this post
https://www.codeproject.com/Articles/392926/Grouping-application-traces-using-ActivityId
Sebastian is using the ActivityId generated by IIS to tied together the different commands executed during his process.
Then I found the source code of HttpRequestMessageExtensions https://github.com/aspnet/AspNetWebStack/blob/master/src/System.Web.Http/HttpRequestMessageExtensions.cs
There, you can see that the method GetCorrelationId() uses the ActivityId to assign a correlation ID to the request.
ActivityId is not completely random. It is tied to the thread started by IIS. I notice that all our request from localhost:port have the same string at the end b63f-84710c7967bb.
We wanted to tied all the commands executed to save an object or retrieve it. So all we needed was a random Guid generated per request. Following the example posted by Sebastian, I stored the current ActivityId in an aux variable, then assigned a new GUID to it, executed Request.GetCorrelationId() and finally assigned back the ID stored in the aux variable to the ActivityId.
In pseudo code =>
Guid prevActivityId = Trace.CorrelationManager.ActivityId
Trace.CorrelationManager.ActivityId = Guid.NewGuid()
...
guid correlation_id = Request.GetCorrelationId()
...
Trace.CorrelationManager.ActivityId = prevActivityId
Hope this is helpful to someone else.

How can I make url path in Swashbuckle/Swaggerwork when api is served from inside another project?

all. I am trying to document a WebApi 2 using Swashbuckle package.
All works great if the API is running by itself i.e. localhost/api/swagger brings me to ui and localhost/api/swagger/docs/v1 to json.
However the producation app initializes this same Webapi project by running webapiconfig method of this project from global.asax.cs in another - now web project (the main application one). So the api url looks like localhost/web/api instead of localhost/api.
Now swashbuckle doesn't work like that at all.
localhost/api/swagger generates error cannot load
'API.WebApiApplication', well of course
localhost/web/swagger = 404
localhost/web/api/swagger = 404
I tried to look everywhere, but all I found is workaround.
c.RootUrl(req => req.RequestUri.GetLeftPart(UriPartial.Authority) + VirtualPathUtility.ToAbsolute("~/").TrimEnd('/'));
Unfortunately it doesn't work, now maybe it should and I just need to change something but I don't even know what exactly this property expects and what it should be set to.
May be it's not even applicable - maybe setup we have requires something else or some swashbuckle code changes.
I will appreciate any help you can provide. I really starting to like swagger (and swashbuckle) for rest documentation.
For Swashbuckle 5.x:
This appears to be set by an extension method of httpConfiguration called EnableSwagger. Swashbuckle 5.x migration readme notes that this replaces SwaggerSpecConfig. SwaggerDocConfig RootUrl() specifically replaces ResolveBasePathUsing() from 4.x.
This practically works the same as it did before, looks like the biggest change was that it was renamed and moved into SwaggerDocConfig:
public void RootUrl(Func<HttpRequestMessage, string> rootUrlResolver)
An example from the readme, tweaked for brevity:
string myCustomBasePath = #"http://mycustombasepath.com";
httpConfiguration
.EnableSwagger(c =>
{
c.RootUrl(req => myCustomBasePath);
// The rest of your additional metadata goes here
});
For Swashbuckle 4.x:
Use SwaggerSpecConfig ResolveBasePathUsing and have your lambda read your known endpoint.
ResolveBasePathUsing:
public SwaggerSpecConfig ResolveBasePathUsing(Func<HttpRequestMessage, string> basePathResolver);
My API is behind a load balancer and this was a helpful workaround to providing a base address. Here's a dumb example to use ResolveBasePathUsing to resolve the path with a known base path.
string myCustomBasePath = #"http://mycustombasepath.com";
SwaggerSpecConfig.Customize(c =>
{
c.ResolveBasePathUsing((req) => myCustomBasePath);
}
I hardcoded the endpoint for clarity, but you can define it anywhere. You can even use the request object to attempt to cleanup your request uri to point to /web/api instead of /api.
The developer commented on this workaround on GitHub last year:
The lambda takes the current HttpRequest (i.e. the request for a given
Swagger ApiDeclaration) and should return a string to be used as the
baseUrl for your Api. For load-balanced apps, this should return the load-balancer path.
The default implementation is as follows:
(req) => req.RequestUri.GetLeftPart(UriPartial.Authority) + req.GetConfiguration().VirtualPathRoot.TrimEnd('/');
...
Re relative paths, the Swagger spec requires absolute paths because
the URL at which the Swagger is being served need not be the URL of
the actual API.
...
The lambda is passed a HttpRequestMessage instance ... you should be able to use this to get at the RequestUri etc. Another option, you could just place the host name in your web.config and have the lambda just read it from there.

How can I safely handle POST parameters in an HTTP Handler using C#?

I'm working on an ASP.Net C# application (my first!) that contains an HTTP Handler within it. My application works with several parameters that are passed in via the URL. My question(s) is as follows:
My applications entry point is via the HTTP Handler. When I enter my ProcessRequest method, I am assigning the values of the URL parameters to variables so that I may do something with the data.
Question: Is this safe, even if I am not setting the value to anything when I call the URL?
In my example: I call host/handler1.ashx instead of host/handler1.ashx?something=foo
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string something = context.Request["something"];
context.Response.Write("Hello World: " + something);
}
When calling the above method using the plain URL with no parameters, it executes just fine, but the string something is just blank/null.
Additional questions:
What happens to the variable something in the case that I do not explicitly initialize it via the URL? I understand that it is null, but can this lead to problems?
Is it dangerous or not safe to call the plain URL (i.e. should I always call it with parameter values specified)?
What is the best way to call a "clean" ashx URL to start the application but not risk problems?
The application will do a series of subsequent GET redirects as it accumulates values and passes them back to the app via the query string.
Should I do a POST or GET upon initial call of the application?
Sorry for asking the same question multiple ways, but I'm a bit confused on the topic and this is my first time writing an app like this. Any patience and advice you could provide on how to safely handle and initialize parameters is greatly appreciated!
There is nothing wrong with omitting parameters to an endpoint. As the developer you are in charge of enforcing what the client is allowed send to you. If you expect a parameter and it's missing, throw an error (e.g. HttpException).
If you are creating or updating data (i.e. inserting or updating records in a database) the best method would be a POST or PUT.
Edit - Here is an example of how you can handle the input:
public void ProcessRequest(HttpContext context) {
//Maybe you require a value?
if (string.IsNullOrEmpty(context.Request["something"])) {
throw new HttpException(400, "You need to send a value!");
}
//Maybe you require a certain value?
if (context.Request["something"] != "beerIsGood") {
throw new HttpException(400, "You need to send the right value!");
}
}
You can't. The Internet is dangerous.

Categories

Resources