Blazor Client Side (WASM) Application Insights - azure-application-insights

Does Application Insights SDK work for Blazor WASM?
I'm trying connect my application but it doesn't send any metrics. Even when instantiating TelemetryClient it's simply hanging.

Unlike Blazor Server-side, you can't just add a singleton into IoC and then inject it to pages. The first thing I tried was this way too! I know, that should be the way... Blazor team needs to handle this behind the scene I think.
But anyway, here is what you should do:
Our approach will assume that we will use the Application Insight javascript SDK.
Copy the snippet mentioned on here: https://learn.microsoft.com/en-us/azure/azure-monitor/app/javascript#snippet-based-setup
(if you are too lazy, find below)
<script type="text/javascript">
!function(T,l,y){var S=T.location,u="script",k="instrumentationKey",D="ingestionendpoint",C="disableExceptionTracking",E="ai.device.",I="toLowerCase",b="crossOrigin",w="POST",e="appInsightsSDK",t=y.name||"appInsights";(y.name||T[e])&&(T[e]=t);var n=T[t]||function(d){var g=!1,f=!1,m={initialize:!0,queue:[],sv:"4",version:2,config:d};function v(e,t){var n={},a="Browser";return n[E+"id"]=a[I](),n[E+"type"]=a,n["ai.operation.name"]=S&&S.pathname||"_unknown_",n["ai.internal.sdkVersion"]="javascript:snippet_"+(m.sv||m.version),{time:function(){var e=new Date;function t(e){var t=""+e;return 1===t.length&&(t="0"+t),t}return e.getUTCFullYear()+"-"+t(1+e.getUTCMonth())+"-"+t(e.getUTCDate())+"T"+t(e.getUTCHours())+":"+t(e.getUTCMinutes())+":"+t(e.getUTCSeconds())+"."+((e.getUTCMilliseconds()/1e3).toFixed(3)+"").slice(2,5)+"Z"}(),iKey:e,name:"Microsoft.ApplicationInsights."+e.replace(/-/g,"")+"."+t,sampleRate:100,tags:n,data:{baseData:{ver:2}}}}var h=d.url||y.src;if(h){function a(e){var t,n,a,i,r,o,s,c,p,l,u;g=!0,m.queue=[],f||(f=!0,t=h,s=function(){var e={},t=d.connectionString;if(t)for(var n=t.split(";"),a=0;a<n.length;a++){var i=n[a].split("=");2===i.length&&(e[i[0][I]()]=i[1])}if(!e[D]){var r=e.endpointsuffix,o=r?e.location:null;e[D]="https://"+(o?o+".":"")+"dc."+(r||"services.visualstudio.com")}return e}(),c=s[k]||d[k]||"",p=s[D],l=p?p+"/v2/track":config.endpointUrl,(u=[]).push((n="SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details)",a=t,i=l,(o=(r=v(c,"Exception")).data).baseType="ExceptionData",o.baseData.exceptions=[{typeName:"SDKLoadFailed",message:n.replace(/\./g,"-"),hasFullStack:!1,stack:n+"\nSnippet failed to load ["+a+"] -- Telemetry is disabled\nHelp Link: https://go.microsoft.com/fwlink/?linkid=2128109\nHost: "+(S&&S.pathname||"_unknown_")+"\nEndpoint: "+i,parsedStack:[]}],r)),u.push(function(e,t,n,a){var i=v(c,"Message"),r=i.data;r.baseType="MessageData";var o=r.baseData;return o.message='AI (Internal): 99 message:"'+("SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details) ("+n+")").replace(/\"/g,"")+'"',o.properties={endpoint:a},i}(0,0,t,l)),function(e,t){if(JSON){var n=T.fetch;if(n&&!y.useXhr)n(t,{method:w,body:JSON.stringify(e),mode:"cors"});else if(XMLHttpRequest){var a=new XMLHttpRequest;a.open(w,t),a.setRequestHeader("Content-type","application/json"),a.send(JSON.stringify(e))}}}(u,l))}function i(e,t){f||setTimeout(function(){!t&&m.core||a()},500)}var e=function(){var n=l.createElement(u);n.src=h;var e=y[b];return!e&&""!==e||"undefined"==n[b]||(n[b]=e),n.onload=i,n.onerror=a,n.onreadystatechange=function(e,t){"loaded"!==n.readyState&&"complete"!==n.readyState||i(0,t)},n}();y.ld<0?l.getElementsByTagName("head")[0].appendChild(e):setTimeout(function(){l.getElementsByTagName(u)[0].parentNode.appendChild(e)},y.ld||0)}try{m.cookie=l.cookie}catch(p){}function t(e){for(;e.length;)!function(t){m[t]=function(){var e=arguments;g||m.queue.push(function(){m[t].apply(m,e)})}}(e.pop())}var n="track",r="TrackPage",o="TrackEvent";t([n+"Event",n+"PageView",n+"Exception",n+"Trace",n+"DependencyData",n+"Metric",n+"PageViewPerformance","start"+r,"stop"+r,"start"+o,"stop"+o,"addTelemetryInitializer","setAuthenticatedUserContext","clearAuthenticatedUserContext","flush"]),m.SeverityLevel={Verbose:0,Information:1,Warning:2,Error:3,Critical:4};var s=(d.extensionConfig||{}).ApplicationInsightsAnalytics||{};if(!0!==d[C]&&!0!==s[C]){method="onerror",t(["_"+method]);var c=T[method];T[method]=function(e,t,n,a,i){var r=c&&c(e,t,n,a,i);return!0!==r&&m["_"+method]({message:e,url:t,lineNumber:n,columnNumber:a,error:i}),r},d.autoExceptionInstrumented=!0}return m}(y.cfg);(T[t]=n).queue&&0===n.queue.length&&n.trackPageView({})}(window,document,{
src: "https://az416426.vo.msecnd.net/scripts/b/ai.2.min.js", // The SDK URL Source
//name: "appInsights", // Global SDK Instance name defaults to "appInsights" when not supplied
//ld: 0, // Defines the load delay (in ms) before attempting to load the sdk. -1 = block page load and add to head. (default) = 0ms load after timeout,
//useXhr: 1, // Use XHR instead of fetch to report failures (if available),
//crossOrigin: "anonymous", // When supplied this will add the provided value as the cross origin attribute on the script tag
cfg: { // Application Insights Configuration
instrumentationKey: "YOUR_INSTRUMENTATION_KEY_GOES_HERE"
/* ...Other Configuration Options... */
}});
</script>
Copy above code into index.html in <head>, ideally before link and script tags
Next, you need to inject IJSRuntime to call JavaScript methods from .Net code.
Inject it like this on top of the page:
#inject IJSRuntime _jsRuntime
Then you can call whatever Application Insight methods you want via like this:
await _jsRuntime.InvokeVoidAsync("appInsights.trackPageView");
You can find the full list of methods for AI JS SDK here:
https://github.com/microsoft/ApplicationInsights-JS/blob/master/API-reference.md
if you don't want to deal with JSRuntime, #IvanJosipovic created a BlazorApplicationInsight library that wraps everything for you.
Simply follow the instructions on his readme file: https://github.com/IvanJosipovic/BlazorApplicationInsights
Sample telemetry results from my Blazor WebAssembly project:
Hope it helps 🤞

Related

How can I get the URL in Google AppMaker?

I am trying to get the current URL in an AppMaker app. However, the standard JavaScript ways do not work, ScriptApp is not available in AppMaker, and the objects that are in AppMaker do not return the correct URL (that starts with https://script.google.com).
Thanks for any suggestions.
You can run a backend/serverside script and use Apps Script
ScriptApp.getService().getUrl()
See the doc ScriptApp Documentation
To have an app URL on client side, you can load it during app startup. Firstly, let's create server script that returns app URL:
/**
* Get the URL of the published web app.
*/
function getAppUrl() {
return ScriptApp.getService().getUrl();
}
Open your Project settings and put next code to App startup script section:
loader.suspendLoad();
google.script.run.withSuccessHandler(function(url) {
appUrl = url;
loader.resumeLoad();
}).getAppUrl();
Now you are able to use appUrl everywhere in Client Scripts.
Using this approach you can create initial app config on startup that requires specific data from server.

400 Error calling WCF web service from Ripple emulator

I tried to bring an old phonegap 1.0 app into VS tool for Apache Cardova. It calls an old WCF XML web service. When I ran the app in Ripple Emulator using local proxy, I got 400 error from the WCF web service. After some digging around, I found the problem in C:\Users\user_name\AppData\Roaming\npm\node_modules\vs-mda\node_modules\ripple-emulator\lib\server\proxy.js line 85-91:
if (Object.keys(req.body).length > 0) {
if (req.is("json")) {
proxyReqData.body = JSON.stringify(req.body);
} else {
proxyReqData.form = req.body;
}
}
If the request is not json, the code would change it to a form so that an XML web service is not supported by the Ripple proxy. I fixed the code at the place, but it was not picked up by the project build. I also do not have a good way to debug my version of proxy.js. Any suggestion would be appreciated.
I figured out the fix myself. The proxy.js that I found is the right location. However, I had to make several changes to proxy.js to make it work with a soap web service. Note that my changes works when you only call soap web services.
Comment out the line with app.use(express.bodyParser()); and replace with it with raw parser in this post: Expressjs raw body
Replace the code block in my question with just:
proxyReqData.form = req.body;

TodoList sample Bing Maps service returns error with status blank

I am working thru the sample todolist application for the Cordova SDK.
the url is here
https://msdn.microsoft.com/en-us/library/dn832630.aspx
I set up a key on the BING Maps website. I can access the location service sending latitude and longitude thru a standard web browser, pasting in the URL with my key.
However the angular call always fails. What is worse is the error is always blank. no status code no error message. Was thinking it must be CORS.
I have run through the sample and downloaded the code sample and both have the same issue.
For anyone going thru the sample. I have realised today that Angular is evil. They say it is nicely testable javascript with dependancy injection, however it doesn't seem to be too interested in telling you what the error is when you have one, it just fails. Great and noble programming ideas, but without an error message it isn't much good.
Anyhow the fix is that Angular is very strict about json code so the line in services.js for the Bings Maps Service method getAddressFromPosition
it used to work with .get() but this was probably an old version of Angular when the demo was written. I tried using 1.2 but the Ripple emulator didn't like references to browser specific code. So I used the latest 1.3.13 I believe.
This is where to access the Bing location service with the Cordova geolocation coordinates returns Json, but Angular wants them wrapped in JSONP. searching the increasing fragmented web it appeared the error might be CORS no, so a many different people had their JSONP calls in controllers, modules, services, some using $http others $resources. Finally using bits and pieces I got JSONP to work with $resources and to plug it into the $promise the call from the controller requires. I used a static Url with Coordinates I knew worked, so you will have to use the :param angular notation to put those back in. Hope it helps someone.
So change to:
getAddressFromPosition: function (position) {
var resource = $resource(url, {}, {
jsonp_query: {
method: 'JSONP'
}
});
return resource.jsonp_query().$promise.then(function (response) {
return response.resourceSets[0].resources[0].address.formattedAddress;
}, function (error) {
return position.coords.latitude + "," + position.coords.longitude
});
edit:
I put the above in and it worked. However the problem was for some reason, perhaps thru debugging, another instance of the app was deployed on another port in ripple. This then change the app to run on this new port. The initial port was 4400. The problem is that and $http or $resource calls in angular have to go thru this emulator, and the emulator was seeing this as cross domain, unless it is configured to the same port the app is running under.
so Url:
http://localhost:4409/index.html?enableripple=cordova-3.0.0-iPhone5
then in the Settings Div dropdown on the right side, the Proxy Port must also be set to 4409 or else the browser will complain that the $http request is cross-domain, before the emulator actually executes it to query Azure mobile service or Bing maps.
So this was very frustrating. However VS Cordova has definately reduced the amount of bits you have to configure to make hybrid mobile apps, there are still little glitches like this which can trip you up. I assumed it was something with angular, because there was no error messages, but in Chrome in the Dev Tools console that was where the error was, and after some googling it was plain that it was the ripple emulator running on a different port than its proxy was not allowing the call to be forwarded on due to Access-Control-Allow not being set.

How do I access Request Parameters in Meteor?

I am planning to use Meteor for a realtime logging application for various
My requirement is pretty simple, I will pass a log Message as request Parameter ( POST Or GET) from various application and Meteor need to simply update a collection.
I need to access Request Parameters in Meteor server code and update Mongo collection with the incoming logMessage. I cannot update Mongo Collection directly from existing applications, so please no replies suggesting the same.I want to know how can I do it from Meteor framework and not doing it by adding more packages.
EDIT: Updated to use Iron Router, the successor to Meteor Router.
Install Iron Router and define a server-side route:
Router.map(function () {
this.route('foo', {
where: 'server',
action: function () {
doSomethingWithParams(this.request.query);
}
});
});
So for a request like http://yoursite.com/foo?q=somequery&src=somesource, the variable this.request.query in the function above would be { q: 'somequery', src: 'somesource' } and therefore you can request individual parameters via this.request.query.q and this.request.query.src and the like. I've only tested GET requests, but POST and other request types should work identically; this works as of Meteor 0.7.0.1. Make sure you put this code inside a Meteor.isServer block or in a file in the /server folder in your project.
Original Post:
Use Meteorite to install Meteor Router and define a server-side route:
Meteor.Router.add('/foo', function() {
doSomethingWithParams(this.request.query);
});
So for a request like http://yoursite.com/foo?q=somequery&src=somesource, the variable this.request.query in the function above would be { q: 'somequery', src: 'somesource' } and therefore you can request individual parameters via this.request.query.q and this.request.query.src and the like. I've only tested GET requests, but POST and other request types should work identically; this works as of Meteor 0.6.2.1. Make sure you put this code inside a Meteor.isServer block or in a file in the /server folder in your project.
I know the questioner doesn't want to add packages, but I think that using Meteorite to install Meteor Router seems to me a more future-proof way to implement this as compared to accessing internal undocumented Meteor objects like __meteor_bootstrap__. When the Package API is finalized in a future version of Meteor, the process of installing Meteor Router will become easier (no need for Meteorite) but nothing else is likely to change and your code would probably continue to work without requiring modification.
I found a workaround to add a router to the Meteor application to handle custom requests.
It uses the connect router middleware which is shipped with meteor. No extra dependencies!
Put this before/outside Meteor.startup on the Server. (Coffeescript)
SomeCollection = new Collection("...")
fibers = __meteor_bootstrap__.require("fibers")
connect = __meteor_bootstrap__.require('connect')
app = __meteor_bootstrap__.app
router = connect.middleware.router (route) ->
route.get '/foo', (req, res) ->
Fiber () ->
SomeCollection.insert(...)
.run()
res.writeHead(200)
res.end()
app.use(router)
Use IronRouter, it's so easy:
var path = IronLocation.path();
As things stand, there isn't support for server side routing or specific actions on the server side when URLs are hit. So it's not easy to do what you want. Here are some suggestions.
You can probably achieve what you want by borrowing techniques that are used by the oauth2 package on the auth branch: https://github.com/meteor/meteor/blob/auth/packages/accounts-oauth2-helper/oauth2_server.js#L100-109
However this isn't really supported so I'm not certain it's a good idea.
Your other applications could actually update the collections using DDP. This is probably easier than it sounds.
You could use an intermediate application which accepts POST/GET requests and talks to your meteor server using DDP. This is probably the technically easiest thing to do.
Maybe this one will help you?
http://docs.meteor.com/#meteor_http_post

Can I request scripts for use in a Spotify app?

I'm trying to use socket.io in my spotify app and the get request for [domain]/socket.io/socket.io.js keeps getting canceled. I've added the domain to the manifest and everything.
Thanks!
Try restarting Spotify. Your app's manifest.json file is loaded when you first view your app, and cached until you quit, even if you modify it.
Note: How external resource permissions work
In order to request external resources, your application needs to specify each domain it plans to connect to in its manifest.json file.
Add a line like this:
{
// ...
"RequiredPermissions": [ "http://*.spotify.com", "http://spotify.com", "http://test.example.com" ]
// ...
}
For the full details check out the Permissions section of the Spotify Apps API Guide.
I can add that when you use socket.io it will try to initialize Flash to check if flash is available so if you find a white box in Spotify (only in Windows), remove the swbobjects initialization in the socket.io.js on the node server.

Resources