Tuesday, November 1, 2016

Migrating to Ionic 2 RC 0 - ngc fails

Finally, I had my app migrated to Ionic 2 RC 0. I tested the app with ionic serve, I built and deployed the app with cordova run - everything was fine.
However, since the beginning of the process was ionic serve, this meant that from an Ionic point of view, everything happened in development mode. So I had no benefit from the performance gain by using Angular's AoT (Ahead-of-time compilation).

So I tried to do a real production build with ionic build. Unfortunately, it produced an error:
[12:51:11]  ionic-app-scripts 0.0.39
[12:51:11]  build prod started ... 
[12:51:11]  clean started ... 
[12:51:11]  clean finished in 7 ms 
[12:51:11]  copy started ... 
[12:51:11]  ngc started ... 
[12:51:11]  copy finished in 455 ms 
[12:51:12]  lint started ... 
[12:51:22]  lint finished in 9.64 s 
[12:51:32]  Error: Error at .../.tmp/app/app.module.ngfactory.ts:415:84 
[12:51:32]  Supplied parameters do not match any signature of call target. 
[12:51:32]  ngc failed 
[12:51:32]  ionic-app-script task: "build" 
[12:51:32]  Error: Error 
I had no idea, what was going wrong... Then I checked line 415 in app.module.ngFactory.ts (a generated file in the .tmp folder:
get _LoggingService_76():import46.LoggingService {
  if ((this.__LoggingService_76 == (null as any))) { (this.__LoggingService_76 = new import46.LoggingService()); }
    return this.__LoggingService_76;
}
Ok, it has something to do with my LoggingService, which I am using as provider in app.module.ts:
@NgModule({
  ...
  providers: [
    ConfigurationService
    LoggingService,
    ...
  ]
})
Then I checked the declaration of the LoggingService:
export declare class LoggingService {
  private configurationService;
  constructor(configurationService: ConfigurationService);
  ...
}
As you can see, its constructor has a parameter, but the code in app.module.ngFactory.ts is using a parameterless constructor.

One workaround could be to changed the parameter to an optional one. A better workaround is to change the declaration of the provider in app.module.ts:
@NgModule({
  ...
  providers: [
    ConfigurationService,
    {
      provide: LoggingService,
      useFactory: getLoggingService,
      deps: [ConfigurationService]
    },  
    ...
  ]
})
The last piece is the factory function:
export function getLoggingService(configurationService: ConfigurationService): LoggingService {
  return new LoggingService(configurationService);
}
That's it. Still a workaround, but working.

Tuesday, October 11, 2016

Ionic 2 - Using predefined colors

Today I wanted to style a list, in which one item could be selected. Such an selected item should have the primary color.

This meant mainly, I had to define a css class, which I assigned to a selected item:
.selected {
  background-color: #387ef5;
  color: #fff;
}
The background-color is the primary color. And as color, I chose something with a good contrast.

However, this approach is not very flexible. After all, Ionic provides SASS variables. So, why not use them?

Well, one reason could be, that the documentation is not complete. But finally, I made it:
  • The color values are defined in src/theme/variables.scss. You find there something like
    $colors: (
      primary:    #387ef5,
      secondary:  #32db64,
      danger:     #f53d3d,
      light:      #f4f4f4,
      dark:       #222,
      favorite:   #69BB7B
    );
  • For using a color value, Ionic provides a SCSS function named color() (defined in node_modules/ionic-angular/themes/ionic.functions.scss):
    .selected {
      background-color: color($colors, primary);
      color: #fff;
    }
  • For the text color, there is a similar function called color-contrast():
    .selected {
      background-color: color($colors, primary);
      color: color-contrast($colors, primary);
    }
  • If you want more control about the contrast color, you can define it by yourself in the color map, e.g.:
    $colors: (
      primary:    (base: #387ef5, contrast: #ff0000),
      ...
    );
    Now the text is red instead of white.

Sunday, October 9, 2016

Migrating to Ionic 2 RC 0 - CommonJS files

After migrating my app to Ionic 2 RC 0, I was able to typescript-compile my app, but the bundling failed with
bundle dev failed:  Module .../node_modules/log4javascript/log4javascript.js does not export getRootLogger 
Finally, after some googling, I found out, that I had to define the so-called custom named exports of log4javascript by myself:
  1. Copy rollup.config.js from node_modules/@ionic/app-scripts/config into my own config directory.
  2. Change my package.json according to the documentation:
    "config": {
      "ionic_rollup": "./config/rollup.config.js"
    },
    
  3. Add configuration for commonjs plugin in rollup.config.js:
    plugins: [
      commonjs({
        include: [
          'node_modules/log4javascript/**',
        ],
        namedExports: {
          'node_modules/log4javascript/log4javascript.js': [
            'Appender', 'BrowserConsoleAppender', 'getLogger', 'getRootLogger', 'Level', 'LoggingEvent', 'logLog', 'PatternLayout'
          ]
        }
      }),
      ...
    ]
    
As you can see, I had to define every single thing I used from log4javascript. Not beautiful, but it works.

Tuesday, October 4, 2016

Migrating to Ionic 2 RC 0 - Custom Config Files

I followed the documentation about Custom Config Files. For this, I copied the rollup.config.js from node_modules/@ionic/app-scripts/config into my own config directory. Then I changed my package.json according to the documentation:
"config": {
  "ionic_rollup": "./config/rollup.config.js"
},
But now the build reported:
Config file "/Users/.../config/rollup.config.js" not found. Using defaults instead.
Error: Cannot find module '../dist/plugins/ng-template'
As every developer, I tried to solve the first message. But the config file was at exact the reported place. Finally, after checking the code, I found it just "misleading". The problem ist the second message. The first line of the copied rollup.config.js was
var ngTemplate = require('../dist/plugins/ng-template').ngTemplate;
Since I moved the file, the relative path didn't work any more. There for I changed the first line to
var ngTemplate = require('../node_modules/@ionic/app-scripts/dist/plugins/ng-template').ngTemplate;
And both error messages were history.

Update 9-Oct-2016: Latest with @ionic/app-scripts@0.0.30, ngTemplate is no longer required by rollup. Therefore the mentioned error does not occur anymore.

Wednesday, March 30, 2016

OWIN on IIS7

I have a long journey behind me with trying to deploy my ASP.NET application using OWIN on IIS7. But finally, I was successful.

Most articles mention:
  • Ensure that Microsoft.Owin.Host.SystemWeb.dll is in the bin folder of the web application
  • Run app pool in V4.0 integrated mode
  • Add runAllManagedModulesForAllRequests to your Web.config:
    <system.webServer>
      <modules runAllManagedModulesForAllRequests="true" />       
    </system.webServer>
Unfortunately, this was not enough for me. The final hint I found in the Katana Wiki. I had to add
app.UseStageMarker(PipelineStage.MapHandler);
to the end of my Startup.Configuration() method. Really important is “the end”.

Some details, you can find in OWIN Middleware in the IIS integrated pipeline. The article describes how the pipelines in OWIN and ASP.NET relate. Very helpful for me was the tracing of the current pipeline stage.

My code was something like
public void Configuration(IAppBuilder app)
{
  app.UseStaticFiles();
  app.MapSignalR();
  app.UseWebApi();
}
With the tracing, I saw the following the following stages on IIS7:
  • UseStaticFiles: AuthorizeRequest
  • MapSignalR: AuthorizeRequest
  • UseWebApi: missing
On IIS8.5, the behavior was slightly different:
  • UseStaticFiles: AuthorizeRequest
  • MapSignalR: AuthorizeRequest
  • UseWebApi: PreExecuteRequestHandler
On IIS8.5, everything was working, but on IIS7, WebApi couldn’t work, since it was not reached in the pipeline.

My first suspicion was, that MapSignalR did prevent the further processing. But this was completely wrong. Due to MapSignalR at least everything before (including SignalR) worked, since MapSignalR is setting the stage marker PostAuthorize.

Unfortunately everything later than MapHandler is not executed on IIS7. Therefore I had to add the appropriate call at the end of my method:
public void Configuration(IAppBuilder app)
{
  app.UseStaticFiles();
  app.MapSignalR();
  app.UseWebApi();
  app.UseStageMarker(PipelineStage.MapHandler);
}
Now everything is working latest in stage MapRequestHandler, in my case:
  • UseStaticFiles: AuthorizeRequest
  • MapSignalR: AuthorizeRequest
  • UseWebApi: MapRequestHandler
Unfortunately, I still do not know, why this is necessary. But at least I have a working solution now.

Tuesday, March 29, 2016

Do not use Microsoft.AspNet.SignalR.Owin any longer

Today I had some strange warnings in one of my web projects using SignalR and Owin. After longer probing and testing, also asking at Stack Overflow, I finally found the reason.

I used the following NuGet packages (beside others):

Both components contain some classes in the same namespace (e.g. Microsoft.AspNet.SignalR.WebSockets.DefaultWebSocketHandler). Unfortunately, not all implementations (worse: not all signatures) are identical. This caused my problems.

The solution is simple: just do not use the NuGet package Microsoft.AspNet.SignalR.Owin any longer! Microsoft.AspNet.SignalR.Core is enough.

Owin Default Files

I just came around the problem that I wanted to serve static files via Owin. Therefore I added the NuGet package Microsoft.Owin.StaticFiles, and added the following to my Startup class:

app.UseStaticFiles();
app.UseDefaultFiles(new DefaultFilesOptions 
  { 
    DefaultFileNames = new[] { "index.html" } 
  });

With this, I was able to serve static files, but the default document didn’t work. I always got a HTTP 404 response. Even though I saw the access to the file in the Process Monitor. Finally, I found the solution in one of the answers to a question of Stack Overflow. I had to call UseDefaultFiles first! Before UseStaticFiles:

app.UseDefaultFiles(new DefaultFilesOptions 
  { 
    DefaultFileNames = new[] { "index.html" } 
  });
app.UseStaticFiles();

Sunday, March 20, 2016

CodeAnalysis broken on TFS build

Today I created a new build on TFS. The compile step was successful, but not the code analysis. It failed with

(RunCodeAnalysis target) ->
  MSBUILD : error : CA0001 : The following error was encountered while reading module '...': Could not resolve member reference: [System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]System.Net.Http.Formatting.BaseJsonMediaTypeFormatter::get_SerializerSettings.

This was quite confusing, since I had referenced the correct version. Since I had the same problem already 4 weeks ago, but couldn’t remember it today, I decided to write this post.

In the detailed build output I found also

Unified primary reference "Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed".
Using this version instead of original version "6.0.0.0" in "...\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll" because AutoUnify is 'true'.

System.Net.Http.Formatting is referencing Newtonsoft.Json in version 6.0.0.0, but I referenced it in version 8.0.0.0. This doesn’t make problems with the build, and also at runtime, there are no problems (due to the assemblyBinding). But code analysis cannot handle it out of the box.

The solution is to enhance the FxCop command with /assemblyCompareMode:StrongNameIgnoringVersion. I did this by adding a property to my .csproj file:

<propertygroup>
  <codeanalysisadditionaloptions>/assemblyCompareMode:StrongNameIgnoringVersion</codeanalysisadditionaloptions>
</propertygroup>

That’s it!