Wednesday, August 24, 2016

Angular And Filtering Exactly

Angular ships with a set of filters for common output transformations (e.g., formatting a date, formatting currency, etc...).

The filter provider also exposes the 'filter' filter. This filter provides a way to query an array of objects based on property values. It's not as sophisticated as LINQ but it's better than nothing.

By default, the filter 'filter' does a substring match instead of an exact match.

For example, the following code snippet:


$filter('filter')([{name: 'one', male: false}, {name: 'two', male: 'trueisms'}, {name: 'three', male: true}], {male: true})

returns a list with 2 objects (male = 'trueisms' and male = true) instead of 1 (which is what I expected). This is because the default filter will return every object with a male property for which true is a substring.

To get exact matching behavior (and thereby return 1 object in the aforementioned example) pass true as the 3rd argument to the $filter('filter')(...) call.


Wednesday, August 17, 2016

Chrome Tip - Searching Every/All Source Files At Once

To search through every source file loaded by the currently viewed web page (e.g., the HTML, JavaScript and CSS) open Chrome Dev Tools. From the Sources tab right click topmost node in the tree then choose "Search in all files".

Given that it's accessed via an element in a tree one wonders if it can be used to search through all source files under a given node? A quick test confirms this!

Wednesday, August 10, 2016

Asynchronous Validation In Angular 1.3*

Problem Introduction

One of Angular 1.3*'s more powerful features is its concept of directives. Directives are, in my opinion, what separate Angular from other frameworks and also contributes to its ease of adoption.

If you have worked with HTML at all then you've applied attributes to HTML elements to alter appearance and/or behavior in some way. Why not augment that with the ability to implement custom attributes?

Why Fix This Now?

The need for an application domain specific, server-based auto-complete/type-ahead text input widget crossed an internal, totally subjective threshold of mine. That threshold, N=3, is the point at which I'd like to start consolidating those 3 separate instances into a reusable component because N=4 is rarely far behind N=3 whereas sometimes N=2 is a fluke...

From a framework agnostic perspective this involves providing the user with a textbox for input then, as they type, querying the server and presenting matching options.

How Can Angular Help?

Angular's facility for handling this is its validation pipeline. While it could be done synchronously part of the rationale for an async-heavy framework like Angular is raising the level of interactivity of web applications.

Client side UI frameworks have had support for the behavior for ages (e.g., a ComboBox).

By using the async validation pipeline the user is able to modify other input, resize the browser, etc...  while waiting for results to update. This increases the perceived interactivity of the application.

How Does Angular's Async Validation Work?

Angular's validation framework is exposed through the Form that is published onto $scope by name (e.g., $scope.myForm when the form tag's name attribute is myForm). The details are well described in the Developer Guide/Forms/Custom Validation section.

A Few Considerations To Keep In Mind

  1. Use the custom validation example as your starting point.
  2. The user should be given some indication of progress while the server-side query is executing.
    1. myForm.$pending.myCustomAsyncValidator is defined (e.g., angular.isDefined() returns true) while the operation is executing. Makes an excellent candidate for an ng-show binding.
  3. The promise returned by the custom validator is a little tricky. If the async call succeeds the then-able promise executes any chained callbacks. But it is very likely that you need to inspect the result of the call to determine if the call's input was valid.
    1. To do this, have your custom validator return $q.reject(reason) from the success callback which will trigger rejection.
  4. If validation is failed (e.g., your validator returns $q.reject(reason)) then the error is published to the form property's error object (e.g., myForm.myProperty.$error.myCustomAsyncValidator evaluates to true).
    1. myForm.$valid will also be false.
  5. If validation succeeds (e.g., your validator returns anything other than a rejected promise) then myForm.myProperty.$error.myCustomAsyncValidator evaluates to false.
    1. This doesn't mean that myForm.$valid will be true. All validators (both synchronous and asynchronous) must successfully resolve for myForm.$valid to be true.

Code Snippets


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
angular.module('myModule').directive('myCustomAsyncValidator', ['$q', function($q) {
  //  ... returns a definition object, most omitted for brevity
  return {
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$asyncValidators.myCustomAsyncValidator = function(modelValue, viewValue) {
        
        // ...
        
        // promise executes the server call using viewValue as input, 
        // omitted for brevity
        
        return promise.then(function(data) {
          if (data.failsValidation) { 
            return $q.reject('input not valid');
          } else {
            return angular.copy(data);
          }
        }); // could also handle case where the server call fails to complete here...
      }
    }
  };
}]);

This directive is applied to the HTML input element as follows:

1
<input type="text" name="myProperty" ng-model="data.myModel.myProperty" my-custom-async-validator>


Wednesday, August 3, 2016

Why won't git ignore .vs/config/applicationhost.config?

In this case, I was trying to ignore anything in the .vs/ folder (mainly to ignore .vs/config/applicationHost.config which is iisexpress' config file). This directory, created by Visual Studio 2015, contains machine specific data (similar to why you don't want to store .suo files in the repository).

The pattern I went with (.vs/) was both what I came up with originally and the same pattern used by the gitignore template for visual studio.

The pattern was stored in .gitconfig in the repository root directory.

But every time I ran git check-ignore --verbose .vs/config/applicationHost.config the file would not match the pattern.

Oddly enough, a different file in .vs/ matched the .gitignore pattern!

It turns out that .gitignore will not match files that have ever been tracked by git. This file was mistakenly checked in at some point in the past. To check .gitignore patterns without regard for checkin history, use the --no-index flag (eg., check-ignore --verbose .vs/config/applicationHost.config).

To stop tracking the file use git rm --cached path/to/file.ext

Tuesday, July 12, 2016

Using ASP.NET Membership with Oracle

So you’ve run the scripts to install the Oracle Providers for ASP.NET. You’ve verified that scripts executed without error. But no matter what you try, the code does not seem to use the OracleMembershipProvider.

The first difference is that the Sql Membership Provider’s root object is Membership while Oracle’s is OracleMembershipProvider.

You’ll quickly notice that the convenience overloads of Membership methods, implemented as extension methods, have not been implemented.

OracleMembershipProvider.CreateUser() - Note that the password question and password answer fields cannot be null (even if they’re not used).

Make sure that the v4 provider dll has been installed into the Global Assembly Cache (via OraProvCfg).

OracleMembershipProvider does not have a static method for constructing new instances (use new OracleMembershipProvider()).

The default constructor does not initialize the object with the settings specified in the application config file. To read those settings call provider.Initialize() with the name you gave the oracle provider in app.config and a non-readonly NameValueCollection containing the membership settings.

But how do we get such a NameValueCollection? Using ConfigurationManager.AppSettings causes an exception indicating that the collection is read-only.

1
2
3
4
5
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);

            NameValueCollection appSettings = ((System.Web.Configuration.MembershipSection)config.GetSection("system.web/membership")).Providers["MyOracleMembershipProvider"].Parameters;

            provider.Initialize("MyOracleMembershipProvider", appSettings);

Wednesday, June 1, 2016

Using the Visual Studio Diagnostics Hub with an Oracle back-end

Anyone else out there extremely stoked about the Diagnostics Tools that shipped with Visual Studio 2015? The visual display that happens in real-time provides a different kind of coverage than the call-graphs and static call tables you usually get with profiling.
My excitement was somewhat tempered by the lack of support for Oracle/ODP.NET clients. Fortunately, since the Diagnostics Hub is based on IntelliTrace and IntelliTrace is very extensible it is possible to get support for Oracle clients in the Diagnostics and Performance Hub with a few simple steps:
  1. Find CollectionPlan.xml in your Visual Studio installation directory (on my installation it’s in Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\IntelliTrace\14.0.0\en).
  2. Add a module specification for Oracle.DataAccess.dll (<ModuleSpecification Id="oracle.dataaccess">Oracle.DataAccess.dll</ModuleSpecification>)
  3. Add DiagnosticsEventSpecifications as listed below (ildasm helps with this part) then exit and restart Visual Studio for the changes to take effect.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
      <DiagnosticEventSpecification>
        <CategoryId>system.data</CategoryId>
        <SettingsName _locID="settingsName.OracleCommand.ExecuteReader2">ExecuteReader (Oracle)</SettingsName>
        <SettingsDescription _locID="settingsDescription.OracleCommand.ExecuteReader2">Command text was executed, building an OracleDataReader using one of the CommandBehavior values.</SettingsDescription>
        <Bindings>
          <Binding>
            <ModuleSpecificationId>oracle.dataaccess</ModuleSpecificationId>
            <TypeName>Oracle.DataAccess.Client.OracleCommand</TypeName>
            <MethodName>ExecuteDbDataReader</MethodName>
            <MethodId>Oracle.DataAccess.Client.OracleCommand.ExecuteDbDataReader(System.Data.CommandBehavior):System.Data.Common.DbDataReader</MethodId>
            <ShortDescription _locID="shortDescription.OracleCommand.ExecuteReader2">Execute Reader "{0}"</ShortDescription>
            <LongDescription _locID="longDescription.OracleCommand.ExecuteReader2">The command text "{0}" was executed on connection "{1}", building an OracleDataReader using one of the CommandBehavior values.</LongDescription>
            <DataQueries>
              <DataQuery index="0" maxSize="4096" type="String" name="Command Text" _locID="dataquery.OracleCommand.ExecuteReader2.CommandText2" _locAttrData="name" query="m_commandText"></DataQuery>
              <DataQuery index="0" maxSize="256" type="String" name="Connection String" _locID="dataquery.OracleCommand.ExecuteNonQuery.ConnectionString" _locAttrData="name" query="m_connection.m_conString"></DataQuery>              
            </DataQueries>
          </Binding>
        </Bindings>
      </DiagnosticEventSpecification>
      <DiagnosticEventSpecification>
        <CategoryId>system.data</CategoryId>
        <SettingsName _locID="settingsName.OracleCommand.ExecuteNonQuery">ExecuteNonQuery (Oracle)</SettingsName>
        <SettingsDescription _locID="settingsDescription.OracleCommand.ExecuteNonQuery">Command text was executed, returning the number of rows affected.</SettingsDescription>
        <Bindings>
          <Binding>
            <ModuleSpecificationId>oracle.dataaccess</ModuleSpecificationId>
            <TypeName>Oracle.DataAccess.Client.OracleCommand</TypeName>
            <MethodName>ExecuteNonQuery</MethodName>
            <MethodId>Oracle.DataAccess.Client.OracleCommand.ExecuteNonQuery():System.Int32</MethodId>
            <ShortDescription _locID="shortDescription.OracleCommand.ExecuteNonQuery">Execute NonQuery "{0}"</ShortDescription>
            <LongDescription _locID="longDescription.OracleCommand.ExecuteNonQuery">The command text "{0}" was executed on connection "{1}", returning the number of rows affected.</LongDescription>
            <DataQueries>
              <DataQuery index="0" maxSize="4096" type="String" name="Command Text" _locID="dataquery.OracleCommand.ExecuteNonQuery.CommandText2" _locAttrData="name" query="m_commandText"></DataQuery>
              <DataQuery index="0" maxSize="256" type="String" name="Connection String" _locID="dataquery.OracleCommand.ExecuteNonQuery.ConnectionString" _locAttrData="name" query="m_connection.m_conString"></DataQuery>
            </DataQueries>
          </Binding>
        </Bindings>
      </DiagnosticEventSpecification>  

Tuesday, May 31, 2016

The res:// Protocol And Phoning Home

Problem

An internal tool phones home.

Why does it phone home?

It’s a WPF app that defers most of the heavy lifting to a web app rendered through a Web Browser control.

Initial Approach

Easy enough – clone the website. But where to host it? The tool needs to run without network access.

Second step

Store the contents of the site in the executable itself. It’s a .NET WPF app and this seems like the sort of problem embedded resources were intended to solve.

Unfortunately the WPF web browser control, a light wrapper around IE’s ActiveX control, doesn’t know* how to read from managed resources. It *does* however, know how to read from native/win32/PE resources.

How do we store a native resource in a .NET executable?

.NET executables conform to the PE (Portable Executable) format that all windows executables use. Native resources (native is a retronym in this case, before .NET this was the only kind of resource) are defined as part of the PE spec.

It turns out that Visual Studio automatically creates a native/win32 resource for console projects. This resource stores the icon that the shell uses to represent the executable. And it allows you to specify this file, a compiled resource file (*.res), instead of having it automatically generated.

But how do we get a compiled resource file?

The resource related tooling in Visual Studio for .NET projects assumes use of .NET resources. These are a totally different kettle of fish than native/win32 resources. The MSDN article “About Resource Files” explains how to create compiled resource files (spoiler alert: there’s a resource compiler).

But HTML content assumes a directory structure

Native resources predate the WWW by several years. There’s no support for hierarchically arranged files. There are resource types (e.g., RT_BITMAP, RT_FONT, etc…) but other than resource type the structure is entirely flat. This necessitated some manual mapping/flattening of the HTML.

The cloned website included javascript, css and image content. Most of the image content was due to the ExtJS javascript library. Other than the image content there were very few links: each of these was manually converted to a res:// link.

CSS allows references to resources (e.g., background images) via its URL function. Modern CSS libraries make heavy use of the URL function. It turns out that there were several dozen files referenced this way. Fortunately URL accepts relative and absolute URLs. These were programmatically flattened, included in the compiled resource (.res) file and the referencing URL function updated with the res:// link.

All of the files, including images (*.png), javascript and style sheets, were included in the compiled resource file as type RT_HTML (#23) yielding internal URLs in the form res://MyExecutableName.exe/#23/MappedFileName.ext.