Trying to query "traces" in Application Insights via the REST API - azure-application-insights

I am attempting to query the Application Insights "traces" data via the API by using the C# example given on the API Quickstart page (https://dev.applicationinsights.io/quickstart) and I think I am having an issue understanding the path to make the call work.
The following was taken from the Quickstart page...
public class QueryAppInsights
{
private const string URL = "https://api.applicationinsights.io/v1/apps/{0}/{1}/{2}?{3}";
public static string GetTelemetry(string appid, string apikey, string queryType, string queryPath, string parameterString)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("x-api-key", apikey);
var req = string.Format(URL, appid, queryType, queryPath, parameterString);
HttpResponseMessage response = client.GetAsync(req).Result;
if (response.IsSuccessStatusCode)
{
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
Console.WriteLine(response.StatusCode);
return response.Content.ReadAsStringAsync().Result;
}
else
{
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
Console.WriteLine(response.StatusCode);
return response.ReasonPhrase;
}
}
}
When I call it using the following parameters I get the following error.
{"error":{"message":"The requested path does not exist","code":"PathNotFoundError"}}
NotFound
public class TestSuite
{
public void CallTest()
{
QueryAppInsights.GetTelemetry("My Application ID", "My API Key", "query", "traces", "timespan=P7D&query=traces%7C%20where%20message%20contains%20%1111a11aa1-1111-11aa-1a1a-11aa11a1a11a%22");
}
}
When I call it replacing the "query" param with "events" I get over 500 rows returned with the following at the top
{"#odata.context":"https://api.applicationinsights.io/v1/apps/GUID PLACE HOLDER/events/$metadata#traces","#ai.messages":[{"code":"AddedLimitToQuery","message":"The query was limited to 500 rows"}
public class TestSuite
{
public void CallTest()
{
QueryAppInsights.GetTelemetry("My Application ID", "My API Key", "events", "traces", "timespan=P7D&query=traces%7C%20where%20message%20contains%20%1111a11aa1-1111-11aa-1a1a-11aa11a1a11a%22");
}
}
When I call it replacing the "events" param with "metrics" I get the following error:
{"error":{"message":"The requested item was not found","code":"ItemNotFoundError","innererror":{"code":"MetricNotFoundError","message":"Metric traces does not exist"}}}
NotFound
public class TestSuite
{
public void CallTest()
{
QueryAppInsights.GetTelemetry("My Application ID", "My API Key", "metrics", "traces", "timespan=P7D&query=traces%7C%20where%20message%20contains%20%1111a11aa1-1111-11aa-1a1a-11aa11a1a11a%22");
}
}
So I don't know if the way I am passing the query is incorrect or if I am trying something that is not possible. The query was taken from the API Explorer page (https://dev.applicationinsights.io/apiexplorer/query) in the "Query" > "GET /query" section and it does work as expected returning the correct row:
traces
| where message contains "1111a11aa1-1111-11aa-1a1a-11aa11a1a11a" (I've replaced the real GUID's with made up ones)

Just in case anyone ever comes across this I wanted to share how I did it successfully. Basically, I was using the wrong URL constant provided by the example on the quickstart (https://dev.applicationinsights.io/quickstart) page. I had to modify it in order to query Traces:
The given example on the quickstart:
private const string URL = "https://api.applicationinsights.io/v1/apps/{0}/{1}/{2}?{3}";
My implementation:
private const string URL = "https://api.applicationinsights.io/v1/apps/{0}/{1}?{2}{3}";
essentially moving the query string params to match what the GET/query API Explorer (https://dev.applicationinsights.io/apiexplorer/query) does when sending a query.

Related

Can I disable model binding and use the raw request body in an action in dotnet core?

I want to setup an endpoint for testing webhooks from third parties. Their documentation is uniformly poor and there is no way ahead of time to tell exactly what I will be getting. What I've done is setup an ApiController that will just take a request and add a row to a table with what they are sending. This lets me at least verify they are calling the webhook, and to see the data so I can program to it.
// ANY api/webook/*
[Route("{*path}")]
public ActionResult Any(string path)
{
string method = Request.Method;
string name = "path";
string apiUrl = Request.Path;
string apiQuery = Request.QueryString.ToString();
string apiHeaders = JsonConvert.SerializeObject(Request.Headers);
string apiBody = null;
using (StreamReader reader = new StreamReader(Request.Body))
{
apiBody = reader.ReadToEnd();
}
Add(method, name, apiUrl, apiQuery, apiHeaders, apiBody);
return new JsonResult(new { }, JsonSettings.Default);
}
This works great, except for this new webhook I am usign that posts as form data so some middleware is reading the body and it ends up null in my code. Is there any way to disable the model processing so I can get at the request body?
You could actually use model binding to your advantage and skip all that stream reading, using the FromBody attribute. Try this:
[Route("{*path}")]
[HttpPost]
public ActionResult Any(string path, [FromBody] string apiBody)

A simple POST request to Web API not hitting the API at all

From my MVC application, I am trying to make a POST request to these sample end-points (actions) in an API controller named MembershipController:
[HttpPost]
public string GetFoo([FromBody]string foo)
{
return string.Concat("This is foo: ", foo);
}
[HttpPost]
public string GetBar([FromBody]int bar)
{
return string.Concat("This is bar: ", bar.ToString());
}
[HttpPost]
public IUser CreateNew([FromBody]NewUserAccountInfo newUserAccountInfo)
{
return new User();
}
Here's the client code:
var num = new WebAPIClient().PostAsXmlAsync<int, string>("api/membership/GetBar", 4).Result;
And here's the code for my WebAPIClient class:
public class WebAPIClient
{
private string _baseUri = null;
public WebAPIClient()
{
// TO DO: Make this configurable
_baseUri = "http://localhost:54488/";
}
public async Task<R> PostAsXmlAsync<T, R>(string uri, T value)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_baseUri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
var requestUri = new Uri(client.BaseAddress, uri);
var response = await client.PostAsXmlAsync<T>(requestUri, value);
response.EnsureSuccessStatusCode();
var taskOfR = await response.Content.ReadAsAsync<R>();
return taskOfR;
}
}
}
I have the following default route defined for the Web API:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
UPDATE
My code breaks into the debugger until the time the PostAsXmlAsync method on the System.Net.HttpClient code is called. However, no request shows up in Fiddler.
However, if I try to compose a POST request in Fiddler or try to fire a GET request via the browser to one of the API end-points, the POST request composed via Fiddler tells me that I am not sending any data and that I must. The browser sent GET request rightly tells me that the action does not support a GET request.
It just seems like the System.Net.HttpClient class is not sending the POST request properly.
One of the most usual problems is that you don't use the appropriate attribute.
Take into account that there are attributes for ASP.NET MVC and ASP.NET Web API with the same name, but which live in different namespaces:
For Web API you must use the one in System.Web.Http
For MVC, the one in System.Web.MVc
This is a very very usual error, and it affects to allkind of things that exist for both MVC and Web API. So you must be very careful when using something which can exists in bith worlds (for example filters, attributes, or dependency injection registration).
I experienced a similar problem (may not be same one though). In my case, I hadn't given name attribute to the input element. I only figured that out when fiddler showed no post data being sent to the server (just like your case)
<input id="test" name="xyz" type="text" />
Adding the name attribute in the input tag fixed my problem.
However, there is one more thing to note. WebAPI does not put form data into parameters directly. Either you have to create an object with those properties and put that object in the parameter of the post controller. Or you could put no parameters at all like this:
[Route("name/add")]
public async Task Post()
{
if (!Request.Content.IsMimeMultipartContent())
{
return;
}
var provider = PostHelper.GetMultipartProvider();
var result = await Request.Content.ReadAsMultipartAsync(provider);
var clientId = result.FormData["xyz"];
...
Try changing the FromBody to FromUri.
If the parameter is a "simple" type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string.
For complex types, Web API tries to read the value from the message body, using a media-type formatter.
Remove FromBody at all and don't make any restrictions in passing parameters (it can be passed at this time either in uri, query string or form submissions (which is kinda a similar to query strings)
[HttpPost]
public string GetFoo(string foo){...}
It will be implicitly parsed and passed.

modify HTTP request URI and HTTP request method with a CXF interceptor

I want to modify HTTP request URI and HTTP request method using a CXF interceptor in a HTTP client.
I have developed something like this:
public class MyInterceptor extends AbstractPhaseInterceptor<Message> {
public MyInterceptor() {
super(Phase.PRE_PROTOCOL);
}
public void handleMessage(Message message) {
// this returns me correct path and method
// String path = (String) message.getExchange().getOutMessage().get(Message.REQUEST_URI);
// String method = (String) message.getExchange().getOutMessage().get(Message.HTTP_REQUEST_METHOD);
// this does not work as expected
String path = (String) message.get(Message.REQUEST_URI);
String method = (String) message.get(Message.HTTP_REQUEST_METHOD);
// do things here
}
}
Why do need I to use exchange/OutMessage to obtain data about current message and I can not use message directly?
How can I edit both values? I tried using message.put(<key>, <value>) and the same with exchange/OutMessage, but nothing is modified.
Coming to the path, you'd always get that value as null, I believe.
You can try following code, to get the actual value of your uri:
String requestURI = (String) message.get(Message.class.getName() + ".REQUEST_URI");

LiveAuthClient broken?

It seems very much that the current version of LiveAuthClient is either broken or something in my setup/configuration is. I obtained LiveSDK version 5.4.3499.620 via Package Manager Console.
I'm developing an ASP.NET application and the problem is that the LiveAuthClient-class seems to not have the necessary members/events for authentication so it's basically unusable.
Notice that InitializeAsync is misspelled aswell.
What's wrong?
UPDATE:
I obtained another version of LiveSDK which is for ASP.NET applications but now I get the exception "Could not find key with id 1" everytime I try either InitializeSessionAsync or ExchangeAuthCodeAsync.
https://github.com/liveservices/LiveSDK-for-Windows/issues/3
I don't think this is a proper way to fix the issue but I don't have other options at the moment.
I'm a little late to the party, but since I stumbled across this trying to solve what I assume is the same problem (authenticating users with Live), I'll describe how I got it working.
First, the correct NuGet package for an ASP.NET project is LiveSDKServer.
Next, getting user info is a multi-step process:
Send the user to Live so they can authorize your app to access their data (the extent of which is determined by the "scopes" you specify)
Live redirects back to you with an access code
You then request user information using the access code
This is described fairly well in the Live SDK documentation, but I'll include my very simple working example below to put it all together. Managing tokens, user data, and exceptions is up to you.
public class HomeController : Controller
{
private const string ClientId = "your client id";
private const string ClientSecret = "your client secret";
private const string RedirectUrl = "http://yourdomain.com/home/livecallback";
[HttpGet]
public ActionResult Index()
{
// This is just a page with a link to home/signin
return View();
}
[HttpGet]
public RedirectResult SignIn()
{
// Send the user over to Live so they can authorize your application.
// Specify whatever scopes you need.
var authClient = new LiveAuthClient(ClientId, ClientSecret, RedirectUrl);
var scopes = new [] { "wl.signin", "wl.basic" };
var loginUrl = authClient.GetLoginUrl(scopes);
return Redirect(loginUrl);
}
[HttpGet]
public async Task<ActionResult> LiveCallback(string code)
{
// Get an access token using the authorization code
var authClient = new LiveAuthClient(ClientId, ClientSecret, RedirectUrl);
var exchangeResult = await authClient.ExchangeAuthCodeAsync(HttpContext);
if (exchangeResult.Status == LiveConnectSessionStatus.Connected)
{
var connectClient = new LiveConnectClient(authClient.Session);
var connectResult = await connectClient.GetAsync("me");
if (connectResult != null)
{
dynamic me = connectResult.Result;
ViewBag.Username = me.name; // <-- Access user info
}
}
return View("Index");
}
}

Facebook authentication response parameters are wrong -> infinite request loop

I an new to the facebook API and after some work I encountered a problem.
First, I am using the facebook SDK for communication with the facebook APIs.
In my app settings I chose that the response of the OAuth dialog should be query string instead of URI fragment.
On my server I got the following code:
void Page_Load()
{
string url = Request.Url.AbsoluteUri;
Facebook.FacebookOAuthResult result = null;
if (!Facebook.FacebookOAuthResult.TryParse(url, out result))
{
string redirectUrl = PivotServer.Helpers.GetFacebookOAuthUrl();
Response.Redirect(redirectUrl);
}
}
And thats my helper method:
public static string GetFacebookOAuthUrl()
{
FacebookOAuthClient oauth = new FacebookOAuthClient
{
AppId = "149637255147166",
AppSecret = "xxx",
RedirectUri = new Uri("http://mydomain.com/")
};
var param = new Dictionary<string, object>
{
{ "response_type", "token" },
{ "display", "popup" }
};
Uri url = oauth.GetLoginUrl(param);
return url.AbsoluteUri;
}
I ran my page on a web server (IIS). When I open the page the first time I am asked to log in to facebook, which is alright, but then I ran into an infinity loop, because the Auth Token Parameter (from facebook) is an URI fragment instead if a query string (which I wanted (see picture above)).
The response URI looks like
http://mydomain.com/#access_token=AAACIGCNwLp4BAMccSoliF5EMGJm0NPldv5GpmBPIm9z7rRuSkiia7BM0uhEn1V88c8uOlWOfGc3C8sFC9tq90Ma0OwIm0tWLNU5BBAZDZD&expires_in=0&base_domain=mydomain.com
instead of
http://mydomain.com/?code=AAACIGCNwLp4BAMccSoliF5EMGJm0NPldv5GpmBPIm9z7rRuSkiia7BM0uhEn1V88c8uOlWOfGc3C8sFC9tq90Ma0OwIm0tWLNU5BBAZDZD&expires_in=0&base_domain=mydomain.com
Is that a bug from the OAuth API, or what am I doing very wrong here?
It's an issue with IE. Be sure to have a p3p header in each response from your server.
It has been too easy:
var param = new Dictionary<string, object>
{
{ "response_type", "code" }, // <--- "code" instead of "token"
{ "display", "popup" }
};

Resources