MiniProfiler: How do I profile an AngularJS + WebAPI app? - angularjs

Cross-posted on the MiniProfiler community.
I'm trying to throw MiniProfiler into my current stack. I think I'm mostly setup, but am missing the UI approach and would like recommendations on the best way to proceed.
Current Stack
SQL for DB (including MiniProfiler tables)
EF 6
WebAPI 2 API app
Angular 1.x. app for the UI (separate app, no MVC backing it) -- I think it's 1.5.x at this point.
So, the current method of RenderIncludes() isn't available to me.
What's the best method to include the JS files and set them up to retrieve the information from the SQL Server storage? I know that the files are included in the UI repo, but I didn't see docs for explicit configuration.
What I've Tried So Far -- Web API App
Installed the MiniProfiler and MiniProfiler.EF6 packages.
Web.Config -- Added Handler
(not sure if this is necessary):
<add name="MiniProfiler" path="mini-profiler-resources/*" verb="*" type="System.Web.Routing.UrlRoutingModule" resourceType="Unspecified" preCondition="integratedMode" />
Added a CORS filter to expose the MiniProfiler IDs to my client app:
public class AddMiniProfilerCORSHeaderFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
actionExecutedContext.Response.Headers.Add("Access-Control-Expose-Headers", "X-MiniProfiler-Ids");
}
}
Add that filter as part of startup:
config.Filters.Add(new AddMiniProfilerCORSHeaderFilter());`
In Global.asax, added to Application_Start():
var connectionString = ConfigurationReader.GetConnectionString(Constants.ConfigSettings.CONNECTION_STRING_NAME);
MiniProfiler.Settings.Storage = new SqlServerStorage(connectionString);
MiniProfilerEF6.Initialize();
Update the begin/end requests:
protected void Application_BeginRequest()
{
if (Request.IsLocal || ConfigurationReader.GetAppSetting(Constants.ConfigSettings.USE_PROFILER, false))
{
var sessionId = Guid.NewGuid().ToString();
MiniProfiler.Start(sessionId);
}
}
protected void Application_EndRequest()
{
MiniProfiler.Stop();
}
What I've tried so far -- client (Angular) App
Snagged the UI files from the Github Repo
Copied the UI directory to my project's output
Reference the CSS:
<link rel="stylesheet" href="js/lib/miniprofiler/includes.css" />
Call the JavaScript
<script async type="text/javascript"
id="mini-profiler"
src="js/lib/miniprofiler/includes.js?v=1.0.0.0"
data-current-id=""
data-path="https://localhost:44378/api/profiler/"
data-children="true"
data-ids=""
data-version="1.0.0.0"
data-controls="true"
data-start-hidden="false"
data-trivial-milliseconds="5">
</script>
Current Status
When I do these things, it looks like it just can't find the appropriate WebAPI controller to render the result. If I can figure out where that controller is or replicate it (as I'm attempting to do currently) I think I'll be in business.

The RenderIncludes function results in a <script> tag being output to the page. It is defined in the UI Repo as include.partial.html and currently looks like this:
<script async type="text/javascript" id="mini-profiler"
src="{path}includes.js?v={version}" data-version="{version}"
data-path="{path}" data-current-id="{currentId}"
data-ids="{ids}" data-position="{position}"
data-trivial="{showTrivial}" data-children="{showChildren}"
data-max-traces="{maxTracesToShow}" data-controls="{showControls}"
data-authorized="{authorized}" data-toggle-shortcut="{toggleShortcut}"
data-start-hidden="{startHidden}" data-trivial-milliseconds="{trivialMilliseconds}">
</script>
This is the piece of Javascript that runs the rendering.
The RenderIncludes function is defined here. It does the following:
Makes sure that you have storage set up
Checks that current request is authorized to view results
Gets the Ids of the unviewed profiles for the current user
Takes the Ids along with any other params that you passed into the function and inserts them into the placeholders in the script defined in include.partial.html
Outputs this <script>
So if you cannot call RenderIncludes, there should be no reason why you cannot just put the script file in place, retrieve the unviewed Ids, but them along with any other setup values you want into the <script> tag, and output the tag.
The key lines of code for retrieving the Id values are:
var ids = authorized
? MiniProfiler.Settings.Storage.GetUnviewedIds(profiler.User)
: new List<Guid>();
ids.Add(profiler.Id);
where profiler is the current instance of MiniProfiler (run on the current request.
You will also probably need to make sure that you can handle the call that the script will make to /mini-profiler-resources/results (passing in the id of the profiler as a param). The guts of this is located here in the GetSingleProfilerResult(HttpContext context) function

Related

Trying to make an image classification model using AutoML Vision run on a website

I've created a classification model using AutoML Vision and tried to use this tutorial to make a small web app to make the model classify an image using the browser.
The code I'm using is basically the same as the tutorial with some slight changes:
<script src="https://unpkg.com/#tensorflow/tfjs"></script>
<script src="https://unpkg.com/#tensorflow/tfjs-automl"></script>
<img id="test" crossorigin="anonymous" src="101_SI_24_23-01-2019_iOS_1187.JPG">
<script>
async function run() {
const model = await tf.automl.loadImageClassification('model.json');
const image = document.getElementById('test');
const predictions = await model.classify(image);
console.log(predictions);
// Show the resulting object on the page.
const pre = document.createElement('pre');
pre.textContent = JSON.stringify(predictions, null, 2);
document.body.append(pre);
}
run();
This index.html file above is located in the same folder of the model files and the image file. The problem is that when I try to run the file I'm receiving this error:
error received
I have no idea what I should do to fix this error. I've tried many things without success, I've only changed the error.
models built with AutoML should not have dynamic ops, but seems that yours does.
if that is truly model designed using AutoML, then AutoML should be expanded to use asynchronous execution.
if model was your own (not AutoML), it would be a simple await model.executeAsync() instead of model.execute(), but in AutoML case, that part is hidden inside AutoML library module inside classify call and that needs to be addressed by tfjs AutoML team.
best to open an issue at https://github.com/tensorflow/tfjs/issues
btw, why post a link to an image containing error message instead of copying the message as text here??

Error Image Upload and Get, Method App\Image::__toString() must not throw an exception, caught Illuminate\Database\Eloquent\JsonEncodingException

I am uploading user profile image which is uploading and moved to storage/app/upload/images folder but when I am trying to display that image, below given error occurs.
Method App\Image::__toString() must not throw an exception, caught Illuminate\Database\Eloquent\JsonEncodingException
Here is my controller function for displaying
public function userProfile() {
$image = Image::all();
return view('frontend.layouts.Profile',compact('image'));
}
My view in which I am displaying image
#foreach($image as $images)
<img style="width:210px ; height: 230px " src="/storage/app/upload/images/{{$images->image}}" >
#endforeach
Please Upload your image in Public directory and then try to access that, it will work fine
There are three ways of making an image available to a user:
1. As a public asset
Here the image is made available to everyone. For instance your website logo, or landing page image would be accessed by all. So there is a url to the image that is easily accessed by all. These sort of files would go straight to public/img/ folder.
2. As a protected image available only if specific url is requested
Here user specific images would be accessed by specific people. Think of your members' personal photos that you want to make available only to the member herself or to some specific person. In this case you would store the images in storage/app/public and make a symlink using the artisan command php artisan storage:link You can read more on this here. Assuming that you store your files using random names using str_random() you would then generate urls to your image using the asset() helper like: echo asset('storage/X3jf5j5b2j3n.jpg'); Given that the file names are random, it would be hard to access this image by everyone excepting those who have the url generated using the asset() helper.
3. As a protected image made available using Intervention library
In this case you would first check if user is logged in and then dynamically load the image using Intervention via another protected route. So in your web routes you would first have the user authorization using auth middleware:
Route::group(['middleware' => 'auth'], function () {
Route::get('user', 'UserController#userProfile');
Route::get('images/{image}', 'UserController#serveImage'); // this route serves the image only if user is logged in
});
Then once your have installed Intervention library using composer, our UserController would look like:
use Intervention;
class UserController extends Controller
{
public function userProfile()
{
$images = Image::all();
return view('frontend.layouts.Profile', compact('images'));
}
public function serveImage($image)
{
$filename = storage_path('app/images/'.$image);
return Intervention::make($filename)->response();
}
}
You can see that the image is now being served from the storage folder and not public folder. So this method serveImage() is called only when the route defined earlier for it is authorized. Intervention then works its magic to read the image and send it as a http response.
Your view would change one tad bit to accommodate the new route end point that we defined called images. I assume here that you are storing the filename of the image in db by a field named filename:
#foreach($images as $image)
<img style="width:210px ; height: 230px " src="{{ url('/images/'.$image->filename) }}" >
#endforeach
Note: Do bear in mind that the preferred way to serve images is by using method 2 since it is much faster. You can use method 3 sparingly if you really don't want anyone to even stumble upon the files using the urls.

Spring + Angular + JAR Build with Command Line Parameter

I am building a UI into a JAR for Spring Server. I have a bunch of Angular JS pages. I want to pass in a command line argument to my jar that tells it where the API server is like so:
java -jar application.jar --api=http://ip:9000
So my application.properties file has:
url=${api:http://localhost:9000}
The way I am currently doing is it just having a hardocoded js config file and on each of my .html pages:
<script src="../js/appName/config.angular.js"></script>
Which contains:
var configData = {
url:"http://localhost:9000"
};
And called in each file:
$scope.apiUrl = configData.url;
How do I tap into the applications.properties file that I can override with my JAR command line parameter during runtime vs. the way it has been coded now.
When you pass a value from command line and the same property name is present in properties file then spring boot overrides the value from command line. So to achieve what you want do something like this
In application.properties
#this is default value
app.url=localhost:8080
Create a class to map the properties value or you can use existing class or something else based on your project structure.
#Component
public class Sample {
#Value("${app.url}")
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Now when your execute a jar with argument --app.url="someserver:9090" the value will be overriden and you can use this value anywhere.
Note it will also work if you try to access the properties value directly in jsp using expression.
Try it, it works. I have used the same thing in my latest project which is a composite microservices and each component need each others url.
[Edit]
Reference : http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Am I getting it right: The client part is delivered by the application? So the part of the last sentence 'during runtime' has more the meaning of 'bootstrap/initial loading', right? One (old school) approach is to provide the entry html (e.g. index.html) through the application (a simple template engine) and provide the needed information with a setter in a JS config object:
// pseudo js code with thymeleaf
<script th:inline="javascript">
/*<![CDATA[*/
myConfig.url = [[${#httpServletRequest.remoteHost}]];
/*]]>*/
</script>
This is just a sample that will only set the remote host name but I think you get the idea.
Side note: I still don't really get why do you have to set this. If the application contains the client code, why do you work with absolute URLs for remote calls? (Disclaimer: I have only experience in Angular(2) and not with AngularJS)

ASP.NET MVC bundle won't update if loaded dynamically

I have an Angular.js application, and, because it is a single page application, I'm loading some scripts dynamically, depending on the user navigation, so I don't get an overload.
The problem is, some of these scripts are uglified and minified in a ASP.NET MVC Bundle, and when I update a source script, the imported bundle never gets updated.
Why that happens, and what can I do to force an update?
Why that happens
The ASP.NET bundle comes with a caching mechanism. When you add the bundle to the page using Scripts.Render, the engine automatically puts a v query string into the bundle URL.
#Scripts.Render("~/bundles/commands")
produces something like:
<script src="/bundles/commands?v=eiR2xO-xX5H5Jbn3dKjSxW7hNCH9DfgZHqGApCP3ARM1"></script>
If this parameter is not provided, the cached result will be returned. If you add the script tag manually, without it, you can face the same caching issue.
Info about the v query string is provided here ("Bundle Caching"), but is not very helpful.
What can I do
You can still load the bundled scripts dynamically, but you will have to add the v parameter. Note that it doesn't work if you try a randomly generated hash (I tried). Thanks to Frison B Alexander, this is possible using this approach:
private static string GetHashByBundlePath(string bundlePath)
{
BundleContext bundleContext = new BundleContext(new HttpContextWrapper(System.Web.HttpContext.Current), BundleTable.Bundles, bundlePath);
Bundle bundle = BundleTable.Bundles.GetBundleFor(bundlePath);
BundleResponse bundleResponse = bundle.GenerateBundleResponse(bundleContext);
Type bundleReflection = bundleResponse.GetType();
MethodInfo method = bundleReflection.GetMethod("GetContentHashCode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
object contentHash = method.Invoke(bundleResponse, null);
return contentHash.ToString();
}
So what you can do is: Return the bundle hash from the ASP.NET view and get it when you need to load the script.
I my application, I created a JS object specific to it:
var appBundles = {
commands: "/bundles/commands?v=eiR2xO-xX5H5Jbn3dKjSxW7hNCH9DfgZHqGApCP3ARM1"
};
Hope this helps!
I had this problem with bundles not updating when I was loading bundles from one MVC app in another MVC app using GTM (sound messed up, but it actually makes sense in the context of multiple MVC apps sharing code between).
What I came up with is what Marcos Lima wrote in his answer, but taken a step further.
I've added a Bundle controller with following code:
public class BundleController : Controller
{
private static string GetHashByBundlePath(string bundlePath)
{
BundleContext bundleContext = new BundleContext(new HttpContextWrapper(System.Web.HttpContext.Current), BundleTable.Bundles, bundlePath);
Bundle bundle = BundleTable.Bundles.GetBundleFor(bundlePath);
BundleResponse bundleResponse = bundle.GenerateBundleResponse(bundleContext);
Type bundleReflection = bundleResponse.GetType();
MethodInfo method = bundleReflection.GetMethod("GetContentHashCode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
object contentHash = method.Invoke(bundleResponse, null);
return contentHash.ToString();
}
public ActionResult Index(string bundleName)
{
string bundlePath = "~/bundles/" + bundleName;
var hash = GetHashByBundlePath(bundlePath);
return RedirectPermanent(bundlePath + "?v=" + hash);
}
}
Then I've added this route:
routes.MapRoute(
name: "Bundle",
url: "Bundle/{bundleName}",
defaults: new { controller = "Bundle", action = "Index" }
);
The end result is that I request the bundles through the controller, but because I do a 301 redirect the Index action is run only once per user and it returns the current version of the bundle and the bundle is then served from browser cache afterwards. When I actually update the bundle I add some query parameter in the request url (in GTM) and all users now get the updated bundle.
Of course, I assume that bundles are placed in ~/bundles/ path, but that should be easy enough to change if yours are placed elsewhere. In fact the route isn't even necessary.

Refreshing web page in real time in sails.js

In my project I am using sails.js. From test1.ejs I am calling a web service which in turn calls another ejs(test2.ejs) using res.view().
Now android user is inputting some values which affects the database and needs to reflect on the web page in real time. I am not able to figure out how this can be achieved using sails.js.
Also I need to even show the android user response and at the same time refresh the web page. In short I want a dynamic UI like share market where any changes on the server is reflected on the front end.
Will I need to use anything else like angularjs?
You can use JavaScript Interface if I understand your problem right.
You should create the class like this:
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
#JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
After this you should connect this interface to your webview like this:
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
Now you can call Java code from JS like this:
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>
Or call JS code from Java like this:
webview.loadUrl("javascript:window.showAndroidToast(\"Hello, World!\")");
More info is available here: https://developer.android.com/guide/webapps/webview.html

Resources