tag:blogger.com,1999:blog-49485521107736976892024-03-19T06:07:35.558+01:00Markus Wagner's Blog about .net and mobile DevelopmentEverything is simple if you just know how to do it...Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.comBlogger31125tag:blogger.com,1999:blog-4948552110773697689.post-37840830512303919252018-02-18T13:25:00.001+01:002018-02-18T13:25:09.412+01:00karma-typescript-es6-transform: Fixing preset problem after upgradingRecently, I upgraded the devDependencies in one of my projects to the current versions. This included an update of karma-typescript-es6-transformfrom version 1.0.2 to 1.0.3. Didn't sound dangorous. But afterwards my tests didn't run by karma any more. I just got:<br />
<br />
<pre class="brush: text">18 02 2018 11:20:49.774:ERROR [karma]: Error: /Users/markus/Development/Ritzlgrmft/ionic-logging-service/node_modules/ionic-configuration-service/dist/index.js: Couldn't find preset "es2015" relative to directory "/Users/markus/Development/Ritzlgrmft/ionic-logging-service/node_modules/ionic-configuration-service/dist"
Transform function:
function (context, callback) {
if (!context.js) {
return callback(undefined, false);
}
if (isEs6(context.js.ast)) {
options.filename = context.filename;
log.debug("Transforming %s", options.filename);
try {
context.source = babel.transform(context.source, options).code;
context.js.ast = acorn.parse(context.source, { sourceType: "module" });
return callback(undefined, true);
}
catch (error) {
return callback(error, false);
}
}
else {
return callback(undefined, false);
}
}
at Transformer.handleError (/Users/markus/Development/Ritzlgrmft/ionic-logging-service/node_modules/karma-typescript/dist/bundler/transformer.js:108:19)
at /Users/markus/Development/Ritzlgrmft/ionic-logging-service/node_modules/karma-typescript/dist/bundler/transformer.js:89:27
at transform (/Users/markus/Development/Ritzlgrmft/ionic-logging-service/node_modules/karma-typescript-es6-transform/dist/transform.js:57:24)
at /Users/markus/Development/Ritzlgrmft/ionic-logging-service/node_modules/karma-typescript/dist/bundler/transformer.js:83:17
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickCallback (internal/process/next_tick.js:104:9)
</pre><br />
Raed more here: <a href="https://gist.github.com/Ritzlgrmft/c2dd4dae9afa61ea93aedb7d34f854ee">karma-typescript-es6-transform: Fixing preset problem after upgrading</a>.Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-70737500880025271452017-12-02T13:30:00.004+01:002017-12-02T13:35:24.583+01:00Fixing RxJS import problems with Ionic's production buildRecently, I upgraded to Ionic 3.9.x, which included an upgrade to Angular 5.x as well. Everything went smooth, even I did not understand the RXJS stuff in Ionic's change log. But... when I did the first time a production build (<b>ionic build --prod</b>), I got a strange error:<br />
<br />
<pre class="brush: text">Error: ./node_modules/rxjs/observable/BoundCallbackObservable.js Module build failed: TypeError: Cannot read property 'type' of undefined at Object.getEffectiveTypeAnnotationNode
</pre><br />
Read more here: <a href="https://gist.github.com/Ritzlgrmft/2f470387f5276035b15f39d191a66081">Fixing RxJS import problems with Ionic's production build</a>.Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-89847631287473241362017-05-01T11:27:00.000+02:002017-05-01T11:28:27.007+02:00Updating from Angular 2.4.8 to 4.0.0Recently, I updated my component <a href="https://github.com/Ritzlgrmft/ionic-logging-service">ionic-logging-service</a> to the Angular version used by Ionic 3.0.0. After installing the new npm packages, I was able to build the component. But… tslint did no longer work. I got<br />
<br />
<pre class="brush: text">.../ionic-logging-service/node_modules/tslint/lib/runner.js:92
throw new Error(messages.join("\n"));
^
Error: Error at .../ionic-logging-service/node_modules/@angular/core/src/change_detection/differs/iterable_differs.d.ts:15:48: Cannot find name 'Iterable'.
at Runner.run (.../ionic-logging-service/node_modules/tslint/lib/runner.js:92:27)
at Object.<anonymous> (.../ionic-logging-service/node_modules/tslint/lib/tslint-cli.js:139:6)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Module.require (module.js:353:17)
at require (internal/module.js:12:17)
at Object.<anonymous> (/Users/markus/Documents/Ritzlgrmft/ionic-logging-service/node_modules/tslint/bin/tslint:3:1)
at Module._compile (module.js:409:26)
</pre>This happens due to <b>Iterable</b>, which is a es2015 feature. I solved it by adding the following to my <b>tsconfig.json</b>:<br />
<br />
<pre class="brush: javascript">"compilerOptions": {
"lib": [
"dom",
"es2015"
],
}
</pre><br />
But now I got a lot of errors like<br />
<br />
<pre class="brush: text">Error: Error at /Users/markus/Documents/Ritzlgrmft/ionic-logging-service/node_modules/@types/es6-shim/index.d.ts:6:14: Duplicate identifier 'PropertyKey’.
</pre><br />
This happens, since <b>es6-shim</b> defines the same types as es2015 lib. Therefore I removed the package <b>@types/es6-shim</b>.<br />
<br />
Now tslint was fine, again. But the karma tests failed. I got the error<br />
<br />
<pre class="brush: text">Error: No provider for "framework:es6-shim"! (Resolving: framework:es6-shim)
</pre><br />
This one was easy, since I uninstalled the package, I had to remove it from the frameworks. But now I got errors like<br />
<br />
<pre class="brush: text">ERROR [compiler.karma-typescript]: node_modules/@angular/core/src/change_detection/differs/default_keyvalue_differ.d.ts(23,15): error TS2304: Cannot find name 'Map'.
ERROR [compiler.karma-typescript]: node_modules/@angular/core/src/change_detection/differs/default_keyvalue_differ.d.ts(27,16): error TS2304: Cannot find name 'Map'.
ERROR [compiler.karma-typescript]: node_modules/@angular/core/src/change_detection/differs/iterable_differs.d.ts(15,48): error TS2304: Cannot find name 'Iterable'.
</pre><br />
Again the problem are the es2015 features. Therefore I had to add the lib to the compilerOptions in karma.conf.js. However, this was not enough, since currently PhantomJS does not support the es2015 features. Therefore I had to add a polyfill to my files:<br />
<br />
<pre class="brush: javascript">files: [
{ pattern:
"src/**/*.+(ts|html)" },
"node_modules/reflect-metadata/Reflect.js",
"node_modules/babel-polyfill/dist/polyfill.js"
}
],
</pre><br />
The used <b>babel-polyfill</b> was already there as a dependency of another package.<br />
<br />
And finally, everything was working as before.Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-53915756039960808222017-03-25T20:03:00.000+01:002017-03-29T20:32:31.215+02:00karma-typescript: Invalid syntax in bundle: 'import' and 'export' may only appear at the top levelAfter upgrading some dependent modules, I got:<br />
<pre class="brush: text">[Error: Invalid syntax in bundle: 'import' and 'export' may only appear at the top level (79532:186) in /var/folders/zk/6bvt6fls7g97ry69c8jykn_h0000gn/T/karma-typescript-bundle-62976QkhHVRO4DC9R.js]
Error: Invalid syntax in bundle: 'import' and 'export' may only appear at the top level (79532:186) in /var/folders/zk/6bvt6fls7g97ry69c8jykn_h0000gn/T/karma-typescript-bundle-62976QkhHVRO4DC9R.js
at writeBundleFile (.../node_modules/karma-typescript/lib/bundler.js:171:23)
at flushQueue (.../node_modules/karma-typescript/lib/bundler.js:99:9)
at bundleQueuedModules (.../node_modules/karma-typescript/lib/bundler.js:94:9)
at invokeFunc (.../node_modules/lodash.debounce/index.js:160:19)
at trailingEdge (.../node_modules/lodash.debounce/index.js:207:14)
at timerExpired [as _onTimeout] (.../node_modules/lodash.debounce/index.js:195:14)
at Timer.listOnTimeout (timers.js:92:15)
</pre><br />
The solution was to:<br />
<ul><li><code>npm install karma-typescript@beta</code> (I am using now <code>3.0.0-beta.2</code>)</li>
<li><code>npm install karma-typescript-es6-transform@latest</code> (I am using <code>1.0.0-beta.6</code>)</li>
<li>add to <code>karmaTypescriptConfig</code>:<br />
<pre class="brush: text">bundlerOptions: {
transforms: [
require("karma-typescript-es6-transform")()
]
}
</pre></li>
</ul>For details see <a href="https://github.com/monounity/karma-typescript/issues/87">How to use es6 library</a>.<br />
Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-4906317753906555172017-03-24T20:36:00.000+01:002017-03-29T20:38:13.916+02:00Upgrading Angular dependencies to the versions used by Ionic 2.2I provide a npm package, which contains a service thought for use in Ionic applications.<br />
This service doesn't have any dependencies to Ionic itself, only to some Angular packages.<br />
Since Ionic 2.2 uses newer versions of Angular (2.4.8 instead of 2.2.1), I updated the<br />
Angular dependencies to the new versions. And then, ngc didn't work anymore. I got a strange error:<pre class="brush: text">Error encountered resolving symbol values statically. Calling function 'NoOpAnimationDriver', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol AnimationDriver.NOOP in .../ionic-configuration-service/node_modules/@angular/platform-browser/src/dom/animation_driver.d.ts, resolving symbol BrowserTestingModule in .../ionic-configuration-service/node_modules/@angular/platform-browser/testing/browser.d.ts, resolving symbol BrowserTestingModule in .../ionic-configuration-service/node_modules/@angular/platform-browser/testing/browser.d.ts
</pre>The error message was not very helpful, also Google did not provide a lot of information.<br />
I found only some posts from end of last year.<br />
<br />
The solution was - finally - quite easy. I had to add a specific <code>tsconfig.aot.json</code>, which is used by <code>ngc</code>.<br />
The differences to the original <code>tsconfig.json</code> are:<pre class="brush: javascript">{
"compilerOptions": {
"module": "es2015"
},
"files": [
"src/index.ts"
],
"angularCompilerOptions": {
"genDir": "aot"
}
}
</pre><ul><li><code>module</code> <code>es2015</code> is needed for tree shaking</li>
<li><code>files</code> defines the entry point</li>
<li><code>genDir</code> specifies where ngc stores its intermediate files</li>
</ul>The last bit was to tell <code>ngc</code> to use the new configuration:<pre class="brush: text">ngc -p tsconfig.aot.json
</pre>For a detailed explanation, just check the <a href="https://angular.io/docs/ts/latest/cookbook/aot-compiler.html">Angular Cookbook</a>.<br />
Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-83353107411288273452017-02-21T20:44:00.000+01:002017-03-29T20:48:35.171+02:00Ionic serve: watch failed: A watch configured to watch the following paths failed to startToday I had the problem that every time, I called <code>ionic serve</code>, I got the following error:<pre class="brush: text">...
[10:28:18] build dev finished in 52.67 s
[10:28:22] watch failed: A watch configured to watch the following paths failed to start. It likely that a file
referenced does not exist:
...\src\**\*.(ts|html|s(c|a)ss)
[10:28:22] dev server running: http://localhost:8100/
</pre>I found the error creation in <code>node_modules\@ionic\app-scripts\dist\watch.js</code>. The function <code>startWatcher</code> rejects the promise, if the start of watching needs more than 3 seconds. This is (roundabout) the timespan between "build dev finished" and "watch failed".<br />
<br />
So I thought my machine might be too slow and increased the timeout value to 30 seconds:<pre class="brush: text">[10:33:49] build dev finished in 53.87 s
[10:34:09] lint finished in 20.95 s
[10:34:19] watch failed: A watch configured to watch the following paths failed to start. It likely that a file
referenced does not exist: ...\src\assets\**\*,
...\src\index.html,
...\src\manifest.json,
...\src\service-worker.js,
...\node_modules\ionicons\dist\fonts\**\*,
...\node_modules\ionic-angular\fonts\**\*,
...\node_modules\ionic-angular\polyfills\polyfills.js,
...\node_modules\sw-toolbox\sw-toolbox.js,
...\environments\api-dwp\settings.json,
...\node_modules\leaflet\dist\leaflet.css
[10:34:19] dev server running: http://localhost:8100/
</pre>As you can see, the error is the same, this time after 30 seconds, but there are more files reported. And indeed, the files <code>...\src\manifest.json</code> and <code>...\src\service-worker.js</code> do not exist. They are part of the default <code>node_modules\@ionic\app-scripts\config\copy.config.js</code>.<br />
<br />
It seems, I have 2 possibilities now:<br />
<ul><li>add the 2 files to my app</li>
<li>modify the <code>copy.config.js</code></li>
</ul><br />
Since I have already a custom <code>copy.config.js</code>, and since I do not want to litter my source code with unneeded files, I used the second approach. In the <code>copy.config.js</code>, I had to override the key <code>copyIndexContent</code> (just remove <code>'{{SRC}}/manifest.json'</code> and <code>'{{SRC}}/service-worker.js'</code>):<pre class="brush: javascript">copyIndexContent: {
src: ['{{SRC}}/index.html'],
dest: '{{WWW}}'
},
</pre>Now <code>ionic serve</code> didn't produce watch errors any more:<pre class="brush: text">[11:19:40] build dev finished in 50.56 s
[11:19:51] watch ready in 62.29 s
[11:19:51] dev server running: http://localhost:8100/
</pre>As you can see, the timespan for starting the watching is 11 seconds. So my modification of <code>node_modules\@ionic\app-scripts\dist\watch.js</code> is still needed.<br />
<br />
<b>Update 23-Feb-2017</b><br />
<br />
Starting with <a href="https://github.com/driftyco/ionic-app-scripts/blob/master/CHANGELOG.md#114-2017-02-23">version 1.1.4</a> of <code>@ionic/app-scripts</code>, there is a new option <code>--startWatchTimeout</code> to the <code>ionic</code> command. Instead of modifying the file <code>node_modules\@ionic\app-scripts\dist\watch.js</code> (which is not very reliable, anyway), it's enough to add the additional parameter: <code>ionic serve --startWatchTimeout 30000</code>.<br />
<br />
See <a href="https://github.com/driftyco/ionic-app-scripts/issues/772">Issue 772</a>.<br />
Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-39300719066754087772016-11-01T16:16:00.000+01:002016-11-01T16:16:07.289+01:00Migrating to Ionic 2 RC 0 - ngc failsFinally, I had my app migrated to Ionic 2 RC 0. I tested the app with <b>ionic serve</b>, I built and deployed the app with <b>cordova run</b> - everything was fine.<br />
However, since the beginning of the process was <b>ionic serve</b>, 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 <a href="https://angular.io/docs/ts/latest/cookbook/aot-compiler.html">AoT (Ahead-of-time compilation)</a>.<br />
<br />
So I tried to do a real production build with <b>ionic build</b>. Unfortunately, it produced an error:<br />
<pre class="brush: text">[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
</pre>I had no idea, what was going wrong... Then I checked line 415 in <b>app.module.ngFactory.ts</b> (a generated file in the <b>.tmp</b> folder:<br />
<pre class="brush: javascript">get _LoggingService_76():import46.LoggingService {
if ((this.__LoggingService_76 == (null as any))) { (this.__LoggingService_76 = new import46.LoggingService()); }
return this.__LoggingService_76;
}
</pre>Ok, it has something to do with my <b>LoggingService</b>, which I am using as provider in <b>app.module.ts</b>:<br />
<pre class="brush: javascript">@NgModule({
...
providers: [
ConfigurationService
LoggingService,
...
]
})
</pre>Then I checked the declaration of the <b>LoggingService</b>:<br />
<pre class="brush: javascript">export declare class LoggingService {
private configurationService;
constructor(configurationService: ConfigurationService);
...
}
</pre>As you can see, its constructor has a parameter, but the code in <b>app.module.ngFactory.ts</b> is using a parameterless constructor.<br />
<br />
One workaround could be to changed the parameter to an optional one. A better workaround is to change the declaration of the provider in <b>app.module.ts</b>:<br />
<pre class="brush: javascript">@NgModule({
...
providers: [
ConfigurationService,
{
provide: LoggingService,
useFactory: getLoggingService,
deps: [ConfigurationService]
},
...
]
})
</pre>The last piece is the factory function:<br />
<pre class="brush: javascript">export function getLoggingService(configurationService: ConfigurationService): LoggingService {
return new LoggingService(configurationService);
}
</pre>That's it. Still a workaround, but working.Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-48123652335171802802016-10-11T20:48:00.000+02:002016-11-01T12:52:44.853+01:00Ionic 2 - Using predefined colorsToday I wanted to style a list, in which one item could be selected. Such an selected item should have the <b>primary</b> color.<br />
<br />
This meant mainly, I had to define a css class, which I assigned to a selected item:<br />
<pre class="brush: html;">.selected {
background-color: #387ef5;
color: #fff;
}
</pre>The <b>background-color</b> is the primary color. And as <b>color</b>, I chose something with a good contrast.<br />
<br />
However, this approach is not very flexible. After all, Ionic provides SASS variables. So, why not use them?<br />
<br />
Well, one reason could be, that the documentation is not complete. But finally, I made it:<br />
<ul><li>The color values are defined in <b>src/theme/variables.scss</b>. You find there something like<br />
<pre class="brush: css;">$colors: (
primary: #387ef5,
secondary: #32db64,
danger: #f53d3d,
light: #f4f4f4,
dark: #222,
favorite: #69BB7B
);</pre></li>
<li>For using a color value, Ionic provides a <b>SCSS</b> function named <b>color()</b> (defined in <b>node_modules/ionic-angular/themes/ionic.functions.scss</b>):<br />
<pre class="brush: css;">.selected {
background-color: color($colors, primary);
color: #fff;
}</pre></li>
<li>For the text color, there is a similar function called <b>color-contrast()</b>:<br />
<pre class="brush: css;">.selected {
background-color: color($colors, primary);
color: color-contrast($colors, primary);
}</pre></li>
<li>If you want more control about the contrast color, you can define it by yourself in the color map, e.g.:<br />
<pre class="brush: css;">$colors: (
primary: (base: #387ef5, contrast: #ff0000),
...
);</pre>Now the text is red instead of white.</li>
</ul>Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-44987688729119087272016-10-09T19:31:00.003+02:002016-11-01T12:56:48.619+01:00Migrating to Ionic 2 RC 0 - CommonJS filesAfter migrating my app to Ionic 2 RC 0, I was able to typescript-compile my app, but the bundling failed with<br />
<pre class="brush: plain;">bundle dev failed: Module .../node_modules/log4javascript/log4javascript.js does not export getRootLogger
</pre>Finally, after some googling, I found out, that I had to define the so-called <a href="https://github.com/rollup/rollup-plugin-commonjs#custom-named-exports">custom named exports</a> of <b>log4javascript</b> by myself:<br />
<ol><li>Copy <b>rollup.config.js</b> from <b>node_modules/@ionic/app-scripts/config</b> into my own <b>config</b> directory. </li>
<li>Change my <b>package.json</b> according to the documentation:<br />
<pre class="brush: javascript;">"config": {
"ionic_rollup": "./config/rollup.config.js"
},
</pre></li>
<li>Add configuration for <b>commonjs</b> plugin in <b>rollup.config.js</b>:<br />
<pre class="brush: javascript;">plugins: [
commonjs({
include: [
'node_modules/log4javascript/**',
],
namedExports: {
'node_modules/log4javascript/log4javascript.js': [
'Appender', 'BrowserConsoleAppender', 'getLogger', 'getRootLogger', 'Level', 'LoggingEvent', 'logLog', 'PatternLayout'
]
}
}),
...
]
</pre></li>
</ol>As you can see, I had to define every single thing I used from <b>log4javascript</b>. Not beautiful, but it works.Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-52355187925718482622016-10-04T20:12:00.001+02:002016-10-09T19:07:32.008+02:00Migrating to Ionic 2 RC 0 - Custom Config FilesI followed the documentation about <a href="https://github.com/driftyco/ionic-app-scripts/blob/master/README.md#custom-config-files">Custom Config Files</a>. For this, I copied the <b>rollup.config.js</b> from <b>node_modules/@ionic/app-scripts/config</b> into my own <b>config</b> directory. Then I changed my <b>package.json</b> according to the documentation:<br />
<pre class="brush: javascript;">"config": {
"ionic_rollup": "./config/rollup.config.js"
},
</pre>But now the build reported:<br />
<pre class="brush: plain;">Config file "/Users/.../config/rollup.config.js" not found. Using defaults instead.
Error: Cannot find module '../dist/plugins/ng-template'
</pre>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 <b>rollup.config.js</b> was<br />
<pre class="brush: javascript;">var ngTemplate = require('../dist/plugins/ng-template').ngTemplate;
</pre>Since I moved the file, the relative path didn't work any more. There for I changed the first line to<br />
<pre class="brush: javascript;">var ngTemplate = require('../node_modules/@ionic/app-scripts/dist/plugins/ng-template').ngTemplate;
</pre>And both error messages were history.<br />
<hr /><b>Update 9-Oct-2016</b>: Latest with <b>@ionic/app-scripts@0.0.30</b>, <b>ngTemplate</b> is no longer required by rollup. Therefore the mentioned error does not occur anymore.<br />
<br />
Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-3589552598019915492016-03-30T19:35:00.000+02:002016-03-30T19:36:54.475+02:00OWIN on IIS7I have a long journey behind me with trying to deploy my ASP.NET application using OWIN on IIS7. But finally, I was successful.<br />
<br />
Most articles mention:<br />
<ul>
<li>Ensure that <b>Microsoft.Owin.Host.SystemWeb.dll</b> is in the bin folder of the web application</li>
<li>Run app pool in V4.0 integrated mode</li>
<li>Add runAllManagedModulesForAllRequests to your Web.config:<br />
<pre class="brush: xml;"><system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer></pre>
</li>
</ul>
Unfortunately, this was not enough for me. The final hint I found in the <a href="https://katanaproject.codeplex.com/wikipage?title=Static%20Files%20on%20IIS">Katana Wiki</a>. I had to add<br />
<pre class="brush: csharp;">app.UseStageMarker(PipelineStage.MapHandler);
</pre>
to the end of my <b>Startup.Configuration()</b> method. Really important is “<b>the end</b>”.<br />
<br />
Some details, you can find in <a href="http://www.asp.net/aspnet/overview/owin-and-katana/owin-middleware-in-the-iis-integrated-pipeline">OWIN Middleware in the IIS integrated pipeline</a>. The article describes how the pipelines in OWIN and ASP.NET relate. Very helpful for me was the tracing of the current pipeline stage.<br />
<br />
My code was something like<br />
<pre class="brush: csharp;">public void Configuration(IAppBuilder app)
{
app.UseStaticFiles();
app.MapSignalR();
app.UseWebApi();
}</pre>
With the tracing, I saw the following the following stages on IIS7:<br />
<ul>
<li><b>UseStaticFiles</b>: <b>AuthorizeRequest</b></li>
<li><b>MapSignalR</b>: <b>AuthorizeRequest</b></li>
<li><b>UseWebApi</b>: <b>missing</b></li>
</ul>
On IIS8.5, the behavior was slightly different:<br />
<ul>
<li><b>UseStaticFiles</b>: <b>AuthorizeRequest</b></li>
<li><b>MapSignalR</b>: <b>AuthorizeRequest</b></li>
<li><b>UseWebApi</b>: <span style="color: red;"><b>PreExecuteRequestHandler</b></span></li>
</ul>
On IIS8.5, everything was working, but on IIS7, WebApi couldn’t work, since it was not reached in the pipeline.<br />
<br />
My first suspicion was, that <b>MapSignalR</b> did prevent the further processing. But this was completely wrong. Due to <b>MapSignalR</b> at least everything before (including SignalR) worked, since <b>MapSignalR</b> is setting the stage marker <b>PostAuthorize</b>.<br />
<br />
Unfortunately everything later than <b>MapHandler</b> is not executed on IIS7. Therefore I had to add the appropriate call at the end of my method:<br />
<pre class="brush: csharp;">public void Configuration(IAppBuilder app)
{
app.UseStaticFiles();
app.MapSignalR();
app.UseWebApi();
app.UseStageMarker(PipelineStage.MapHandler);
}
</pre>
Now everything is working latest in stage MapRequestHandler, in my case:<br />
<ul>
<li><b>UseStaticFiles</b>: <b>AuthorizeRequest</b></li>
<li><b>MapSignalR</b>: <b>AuthorizeRequest</b></li>
<li><b>UseWebApi</b>: <span style="color: red;"><b>MapRequestHandler</b></span></li>
</ul>
Unfortunately, I still do not know, why this is necessary. But at least I have a working solution now.Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-80563549726937493992016-03-29T19:20:00.000+02:002016-03-29T19:20:07.319+02:00Do not use Microsoft.AspNet.SignalR.Owin any longerToday I had some strange warnings in one of my web projects using SignalR and Owin. After longer probing and testing, also <a href="http://stackoverflow.com/questions/36279824/duplicate-definitions-in-microsoft-aspnet-signalr-core-and-microsoft-aspnet-sign">asking at Stack Overflow</a>, I finally found the reason.<br />
<br />
I used the following NuGet packages (beside others):<br />
<ul><li><a href="http://www.nuget.org/packages/Microsoft.AspNet.SignalR.Core/2.2.0">Microsoft.AspNet.SignalR.Core: 2.2.0</a></li>
<li><a href="http://www.nuget.org/packages/Microsoft.AspNet.SignalR.Owin/1.2.2">Microsoft.AspNet.SignalR.Owin: 1.2.2</a></li>
</ul><br />
Both components contain some classes in the same namespace (e.g. <code>Microsoft.AspNet.SignalR.WebSockets.DefaultWebSocketHandler</code>). Unfortunately, not all implementations (worse: not all signatures) are identical. This caused my problems.<br />
<br />
The solution is simple: just do not use the NuGet package <a href="http://www.nuget.org/packages/Microsoft.AspNet.SignalR.Owin/">Microsoft.AspNet.SignalR.Owin</a> any longer! <a href="http://www.nuget.org/packages/Microsoft.AspNet.SignalR.Core/">Microsoft.AspNet.SignalR.Core</a> is enough.Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-74834464495701302152016-03-29T19:02:00.003+02:002016-03-29T19:04:20.302+02:00Owin Default Files<p>I just came around the problem that I wanted to serve static files via Owin. Therefore I added the NuGet package <b>Microsoft.Owin.StaticFiles</b>, and added the following to my Startup class:</p><pre class="brush: csharp;">app.UseStaticFiles();
app.UseDefaultFiles(new DefaultFilesOptions
{
DefaultFileNames = new[] { "index.html" }
});
</pre><p>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 <a href="http://stackoverflow.com/questions/25478222/how-to-set-default-static-web-page-for-katana-owin-self-hosted-app">answers to a question of Stack Overflow</a>. I had to call <b>UseDefaultFiles</b> first! Before <b>UseStaticFiles</b>:</p><pre class="brush: csharp;">app.UseDefaultFiles(new DefaultFilesOptions
{
DefaultFileNames = new[] { "index.html" }
});
app.UseStaticFiles();
</pre>Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-76566559636433903532016-03-20T13:56:00.000+01:002016-03-20T14:11:12.213+01:00CodeAnalysis broken on TFS build<p>Today I created a new build on TFS. The compile step was successful, but not the code analysis. It failed with<br />
</p><pre class="brush: plain;">(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.
</pre><p>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.<br />
</p><p>In the detailed build output I found also<br />
</p><pre class="brush: plain;">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'.
</pre><p>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.<br />
</p><p>The solution is to enhance the FxCop command with /assemblyCompareMode:StrongNameIgnoringVersion. I did this by adding a property to my .csproj file:<br />
</p><pre class="brush: xml;"><propertygroup>
<codeanalysisadditionaloptions>/assemblyCompareMode:StrongNameIgnoringVersion</codeanalysisadditionaloptions>
</propertygroup>
</pre><p>That’s it!<br />
</p>Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-24917463469055778862014-10-26T15:26:00.000+01:002014-10-26T15:28:43.912+01:00Problem with id="global" in HTML<p>I am a fan of <a href="http://momentjs.com/" target="_blank">Moment.js</a>. I am using is quite often for formatting dates in my <a href="http://knockoutjs.com/" target="_blank">Knockout</a> view models. <p>In my current project I made some changes, and suddenly, it didn’t work any longer. I only got the exception <ul><li>TypeError: Object expected (Internet Explorer)<br />
<li>ReferenceError: moment is not defined (Chrome & Firefox)</li><br />
<br />
</ul><p>I ended up with deleting nearly everything in my page - until it worked again. So I found out the reason (after hours): I had added the following element:<pre class="brush: xml;"><div id="global"> ... </div>
</pre><p>And this confused Moment.js. Because Moment.js contains support for <a href="http://nodejs.org/" target="_blank">Node.js</a>:<pre class="brush: js;">var moment,
VERSION = '2.8.2',
// the global-scope this is NOT the global object in Node.js
globalScope = typeof global !== 'undefined' ? global : this,
...
</pre><p>That means with my div, globalScope will be set to this div, which doesn’t provide the expected functionality. So my lesson is to never use the id “global” again in my HTML code – at least as long as I can remember this problem.</p><p>I hope this post helps to remember.</p>Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-36562931891480665362014-03-09T12:29:00.001+01:002016-03-20T14:12:03.039+01:00Corrupt user.config file<p>Sometimes – fortunately very seldom – I have the problem that the <b>user.config</b> file is corrupt. When it happens, I get something like<pre class="brush: plain;">System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize
---> System.Configuration.ConfigurationErrorsException: Root element is missing. (C:\Users\_user_\AppData\Local\_appdomain_evidenceType_evidenceHash_\_version_\user.config)
---> System.Xml.XmlException: Root element is missing.
</pre><p>The problem is that in this case I cannot access any setting. No <b>userSettings</b> and also no <b>applicationSettings</b>.<br />
<p>The recommended solution is to delete the <b>user.config</b> file in this case. This is easy since the exception contains the complete file name. And the user has also the permission to delete the file.<br />
<p>However, I didn’t want to bother the user. I thought my program could do the same stuff by itself. Therefore I added the following coding at the beginning of my program (before the first setting will be accessed):<br />
<p><pre class="brush: csharp;">bool isConfigurationValid = false;
while (!isConfigurationValid)
{
try
{
// access one arbitrary setting
var x = Settings.Default.Dummy;
// leave while loop
isConfigurationValid = true;
}
catch (ConfigurationErrorsException e)
{
ConfigurationErrorsException innerException = e.InnerException as ConfigurationErrorsException;
if (innerException != null && innerException.Filename.EndsWith("user.config"))
{
File.Delete(innerException.Filename);
Settings.Default.Reload();
}
else
// other exception; will be not handled here
throw;
}
}
</pre>The idea was to catch an eventual <b>ConfigurationErrorsException</b> and to delete the corrupt <b>user.config</b> file. So far it worked. But after deleting the file I wanted to reload the settings. And this did not work. The corrupt <b>user.config</b> file remained cached. I also replaced the call of <b>Reload()</b> with <b>Reset()</b> or <b>Upgrade()</b>, but the result remained the same.<br />
<p>The solution was to load the settings explicitly (not via <b>Settings.Default</b>). Instead I used <b>ConfigurationManager.OpenExeConfiguration()</b>. Also this method throws an error when one <b>user.config</b> file is corrupt. But it has no influence on <b>Settings.Default</b>:<pre class="brush: csharp;">bool isConfigurationValid = false;
while (!isConfigurationValid)
{
try
{
AppSettingsSection appSettings = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).AppSettings;
isConfigurationValid = true;
}
catch (ConfigurationErrorsException e)
{
if (e.Filename.EndsWith("user.config"))
File.Delete(e.Filename);
}
}
</pre><p>This coding has the additional advantage that I do not have to handle the nested <b>ConfigurationErrorsException</b>s. It is only important to call it before the first access to <b>Settings.Default</b>.</p>Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-89217851634966177302014-03-08T14:13:00.000+01:002014-03-08T14:16:28.289+01:00Working with SqlAzureExecutionStrategy One of my favorite features of Entity Framework 6 was the <a href="http://msdn.microsoft.com/en-us/library/system.data.entity.sqlserver.sqlazureexecutionstrategy.aspx">SqlAzureExecutionStrategy</a>. At least I thought this. I wanted to use it also in my company’s network since we get periodically timeouts connecting to a SQL Server instance (SQL Server 2008 in this case). So I thought, perfect, the <b>SqlAzureExecutionStrategy</b> is the solution to my problem. However, it didn’t work. So I had to investigate...<br />
<br />
My approach was to write a sample program starting two tasks:<br />
<ul><li>Task 1 should open a transaction, update a database row and then wait for some time (without committing or rolling back the transaction)</li>
<li>Task 2 should try to modify the same database row during Task 1’s wait time</li>
</ul>Without any further preparation, this approach raised an exception in Task 2:<br />
<pre class="brush: text">System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out
</pre>Next I added my own implementation of <a href="http://msdn.microsoft.com/en-us/library/system.data.entity.sqlserver.sqlazureexecutionstrategy.aspx">DbConfiguration</a>, which simply configured the execution strategy:<br />
<pre class="brush: csharp">public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
this.SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy());
}
}
</pre>Unfortunately, this approach did not work since the "retrying execution strategies" do not support user-initiated transactions (see <a href="http://msdn.microsoft.com/en-us/data/dn307226">Limitations with Retrying Execution Strategies (EF6 onwards)</a>). To my rescue, the mentioned article describes also a workaround which prevents the usage of the <b>SqlAzureExecutionStrategy</b> together with the transaction:<br />
<pre class="brush: csharp">public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
this.SetExecutionStrategy("System.Data.SqlClient", () => SuspendExecutionStrategy
? (IDbExecutionStrategy)new DefaultExecutionStrategy()
: new SqlAzureExecutionStrategy());
}
public static bool SuspendExecutionStrategy
{
get { return (bool?)CallContext.LogicalGetData("SuspendExecutionStrategy") ?? false; }
set { CallContext.LogicalSetData("SuspendExecutionStrategy", value); }
}
}
</pre>Now the program was running again, but I still got the <b>SqlException</b> with the timeout. Therefore I now added some database logging, another great feature of Entity Framework 6 (see <a href="http://msdn.microsoft.com/en-us/data/dn469464">Logging and Intercepting Database Operations</a>). The log was interesting, since it provided some additional insights. But with my special problem, it was not really useful.<br />
<pre><span style="color: lime;">10:49:56,117 Task 1: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
10:49:56,119 Task 1: -- @0: '3/5/2014 10:49:56 AM' (Type = DateTime2)
10:49:56,119 Task 1: -- @1: '3621840d-724e-4a62-b22a-accb215dfb1b' (Type = Guid)
10:49:56,120 Task 1: -- Executing at 3/5/2014 10:49:56 AM +01:00
10:49:56,130 Task 1: -- Completed in 6 ms with result: 1</span>
<span style="color: blue;">10:49:56,430 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
10:49:56,431 Task 2: -- @0: '3/5/2014 10:49:56 AM' (Type = DateTime2)
10:49:56,431 Task 2: -- @1: '3621840d-724e-4a62-b22a-accb215dfb1b' (Type = Guid)
10:49:56,431 Task 2: -- Executing at 3/5/2014 10:49:56 AM +01:00
10:50:01,557 Task 2: -- Failed in 5124 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: red;">10:50:01,732 Task 2: update failed
System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
The statement has been terminated. ---> System.ComponentModel.Win32Exception: The wait operation timed out</span>
</pre>Then I had a look at the source code of <a href="https://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework.SqlServer/SqlAzureExecutionStrategy.cs">SqlAzureExecutionStrategy</a>. Its implementation consists of mainly one method:<br />
<pre class="brush: csharp">protected override bool ShouldRetryOn(Exception exception)
{
return SqlAzureRetriableExceptionDetector.ShouldRetryOn(exception);
}
</pre>Since the method is protected, I decided to implement my own strategy derived from <b>SqlAzureExecutionStrategy</b>. In the first step, I simply implemented my own <b>ShouldRetryOn</b> method, which I used for setting a breakpoint. I found out that the method was called with the <b>SqlException</b>, but <b>SqlAzureExecutionStrategy</b>'s implementation returned <b>false</b>.<br />
<br />
<b>SqlAzureExecutionStrategy</b> delegates the check of the exception to <a href="https://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework.SqlServer/SqlAzureRetriableExceptionDetector.cs">SqlAzureRetriableExceptionDetector</a>. As you can see in the source code, it returns <b>true</b> for <b>TimeoutException</b> and for <b>SqlException</b> with a specific <a href="http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlerror.aspx">SqlError</a>. However, "my" <b>SqlException</b> has a <b>SqlError</b> with Number == -2, for which <b>false</b> is returned.<br />
<br />
Now I added some real logic to my strategy:<br />
<pre class="brush: csharp">protected override bool ShouldRetryOn(Exception exception)
{
bool shouldRetry = false;
SqlException sqlException = exception as SqlException;
if (sqlException != null)
{
foreach (SqlError error in sqlException.Errors)
{
if (error.Number == -2)
shouldRetry = true;
}
}
shouldRetry = shouldRetry || base.ShouldRetryOn(exception);
Logger.WriteLog("ShouldRetryOn: " + shouldRetry);
return shouldRetry;
}
</pre>With this implementation I had two benefits:<br />
<ul><li>The connection attempt was retried also in my deadlock scenario.<br />
</li>
<li>I got a log entry for every retry.<br />
</li>
</ul>Now I got a "beautiful" trace of my retry activities. And also an explicit exception, when the problem couldn’t be solved by simply retrying it: <br />
<pre><span style="color: lime;">10:56:15,805 Task 1: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
10:56:15,807 Task 1: -- @0: '3/5/2014 10:56:15 AM' (Type = DateTime2)
10:56:15,808 Task 1: -- @1: '4e3554be-1e13-461b-af12-848575317beb' (Type = Guid)
10:56:15,808 Task 1: -- Executing at 3/5/2014 10:56:15 AM +01:00
10:56:15,816 Task 1: -- Completed in 5 ms with result: 1</span>
<span style="color: blue;">10:56:15,823 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
10:56:15,824 Task 2: -- @0: '3/5/2014 10:56:15 AM' (Type = DateTime2)
10:56:15,824 Task 2: -- @1: '4e3554be-1e13-461b-af12-848575317beb' (Type = Guid)
10:56:15,824 Task 2: -- Executing at 3/5/2014 10:56:15 AM +01:00
10:56:20,949 Task 2: -- Failed in 5123 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">10:56:21,046 MyExecutionStrategy: retrying</span>
<span style="color: blue;">10:56:21,051 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
10:56:21,051 Task 2: -- @0: '3/5/2014 10:56:15 AM' (Type = DateTime2)
10:56:21,052 Task 2: -- @1: '4e3554be-1e13-461b-af12-848575317beb' (Type = Guid)
10:56:21,052 Task 2: -- Executing at 3/5/2014 10:56:21 AM +01:00
10:56:26,137 Task 2: -- Failed in 5083 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">10:56:26,219 MyExecutionStrategy: retrying</span>
<span style="color: blue;">10:56:27,241 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
10:56:27,241 Task 2: -- @0: '3/5/2014 10:56:15 AM' (Type = DateTime2)
10:56:27,242 Task 2: -- @1: '4e3554be-1e13-461b-af12-848575317beb' (Type = Guid)
10:56:27,242 Task 2: -- Executing at 3/5/2014 10:56:27 AM +01:00
10:56:32,323 Task 2: -- Failed in 5080 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">10:56:32,404 MyExecutionStrategy: retrying</span>
<span style="color: blue;">10:56:35,653 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
10:56:35,653 Task 2: -- @0: '3/5/2014 10:56:15 AM' (Type = DateTime2)
10:56:35,653 Task 2: -- @1: '4e3554be-1e13-461b-af12-848575317beb' (Type = Guid)
10:56:35,654 Task 2: -- Executing at 3/5/2014 10:56:35 AM +01:00
10:56:40,737 Task 2: -- Failed in 5083 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">10:56:40,822 MyExecutionStrategy: retrying</span>
<span style="color: blue;">10:56:47,901 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
10:56:47,901 Task 2: -- @0: '3/5/2014 10:56:15 AM' (Type = DateTime2)
10:56:47,901 Task 2: -- @1: '4e3554be-1e13-461b-af12-848575317beb' (Type = Guid)
10:56:47,902 Task 2: -- Executing at 3/5/2014 10:56:47 AM +01:00
10:56:52,982 Task 2: -- Failed in 5080 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">10:56:53,066 MyExecutionStrategy: retrying</span>
<span style="color: blue;">10:57:08,527 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
10:57:08,529 Task 2: -- @0: '3/5/2014 10:56:15 AM' (Type = DateTime2)
10:57:08,530 Task 2: -- @1: '4e3554be-1e13-461b-af12-848575317beb' (Type = Guid)
10:57:08,531 Task 2: -- Executing at 3/5/2014 10:57:08 AM +01:00
10:57:13,615 Task 2: -- Failed in 5082 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">10:57:13,699 MyExecutionStrategy: retrying</span>
<span style="color: red;">10:57:13,745 Task 2: update failed
System.Data.Entity.Infrastructure.RetryLimitExceededException: Maximum number of retries (5) exceeded while executing database operations with 'MyExecutionStrategy'. See inner exception for the most recent failure. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server
is not responding.
The statement has been terminated. ---> System.ComponentModel.Win32Exception: The wait operation timed out</span>
</pre>As you can see, the <b>System.Data.Entity.Infrastructure.DbUpdateException</b> was changed now into a <b>System.Data.Entity.Infrastructure.RetryLimitExceededException</b>. The inner <b>System.Data.Entity.Core.UpdateException</b> remains the same.<br />
<br />
My final issue was that I did misunderstand the optional parameters of <b>SqlAzureExecutionStrategy</b>: <b>maxRetryCount</b> is simply the maximum number of retries. But with <b>maxDelay</b> it is more complicated. The delay between the retries is connected to retry number and the power of 2. This results in the following delay intervals (ignoring some minor random stuff):<br />
0, 1, 3, 7, 15, 31, 63, ... (seconds)<br />
You can see the delay also in the trace above: the timespan between "<b>MyExecutionStrategy: retrying</b>" and "<b>Task 2: UPDATE ...</b>".<br />
<br />
<b>maxDelay</b> does not set the duration of the complete operation (from first try until last retry). This was my expectation. Instead it limits only the delay between two retries. With a <b>maxDelay</b> of 5, we get par example:<br />
0, 1, 3, 5, 5, 5, 5, ...<br />
<br />
In the last trace, you can see the decreased <b>maxDelay</b>. And also the final success, since here Task 1 rolls back after 50 seconds:<br />
<pre><span style="color: lime;">11:06:39,953 Task 1: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
11:06:39,955 Task 1: -- @0: '3/5/2014 11:06:39 AM' (Type = DateTime2)
11:06:39,955 Task 1: -- @1: 'c5da0be6-a4a8-4018-9c8f-c1062aa9a958' (Type = Guid)
11:06:39,955 Task 1: -- Executing at 3/5/2014 11:06:39 AM +01:00
11:06:39,964 Task 1: -- Completed in 4 ms with result: 1</span>
<span style="color: blue;">11:06:39,971 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
11:06:39,971 Task 2: -- @0: '3/5/2014 11:06:39 AM' (Type = DateTime2)
11:06:39,972 Task 2: -- @1: 'c5da0be6-a4a8-4018-9c8f-c1062aa9a958' (Type = Guid)
11:06:39,972 Task 2: -- Executing at 3/5/2014 11:06:39 AM +01:00
11:06:45,097 Task 2: -- Failed in 5123 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">11:06:45,193 MyExecutionStrategy: retrying</span>
<span style="color: blue;">11:06:45,199 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
11:06:45,199 Task 2: -- @0: '3/5/2014 11:06:39 AM' (Type = DateTime2)
11:06:45,199 Task 2: -- @1: 'c5da0be6-a4a8-4018-9c8f-c1062aa9a958' (Type = Guid)
11:06:45,200 Task 2: -- Executing at 3/5/2014 11:06:45 AM +01:00
11:06:50,283 Task 2: -- Failed in 5082 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">11:06:50,368 MyExecutionStrategy: retrying</span>
<span style="color: blue;">11:06:51,427 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
11:06:51,427 Task 2: -- @0: '3/5/2014 11:06:39 AM' (Type = DateTime2)
11:06:51,427 Task 2: -- @1: 'c5da0be6-a4a8-4018-9c8f-c1062aa9a958' (Type = Guid)
11:06:51,428 Task 2: -- Executing at 3/5/2014 11:06:51 AM +01:00
11:06:56,510 Task 2: -- Failed in 5080 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">11:06:56,593 MyExecutionStrategy: retrying</span>
<span style="color: blue;">11:06:59,686 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
11:06:59,687 Task 2: -- @0: '3/5/2014 11:06:39 AM' (Type = DateTime2)
11:06:59,687 Task 2: -- @1: 'c5da0be6-a4a8-4018-9c8f-c1062aa9a958' (Type = Guid)
11:06:59,687 Task 2: -- Executing at 3/5/2014 11:06:59 AM +01:00
11:07:04,772 Task 2: -- Failed in 5083 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">11:07:04,853 MyExecutionStrategy: retrying</span>
<span style="color: blue;">11:07:09,858 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
11:07:09,858 Task 2: -- @0: '3/5/2014 11:06:39 AM' (Type = DateTime2)
11:07:09,859 Task 2: -- @1: 'c5da0be6-a4a8-4018-9c8f-c1062aa9a958' (Type = Guid)
11:07:09,859 Task 2: -- Executing at 3/5/2014 11:07:09 AM +01:00
11:07:14,939 Task 2: -- Failed in 5079 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">11:07:15,023 MyExecutionStrategy: retrying</span>
<span style="color: blue;">11:07:20,028 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
11:07:20,029 Task 2: -- @0: '3/5/2014 11:06:39 AM' (Type = DateTime2)
11:07:20,030 Task 2: -- @1: 'c5da0be6-a4a8-4018-9c8f-c1062aa9a958' (Type = Guid)
11:07:20,031 Task 2: -- Executing at 3/5/2014 11:07:20 AM +01:00
11:07:25,113 Task 2: -- Failed in 5080 ms with error: Timeout expired. The timeout period elapsed pr...</span>
<span style="color: orange;">11:07:25,196 MyExecutionStrategy: retrying</span>
11:07:29,968 Task 1: rolling back
11:07:29,975 Task 1: rolled back
<span style="color: blue;">11:07:30,201 Task 2: UPDATE [dbo].[T_Message] SET [LastUpdate] = @0 WHERE ([Messageid] = @1)
11:07:30,202 Task 2: -- @0: '3/5/2014 11:06:39 AM' (Type = DateTime2)
11:07:30,204 Task 2: -- @1: 'c5da0be6-a4a8-4018-9c8f-c1062aa9a958' (Type = Guid)
11:07:30,204 Task 2: -- Executing at 3/5/2014 11:07:30 AM +01:00
11:07:30,208 Task 2: -- Completed in 2 ms with result: 1</span>
</pre>FInally, I was even more enthusiatstic with <b>SqlAzureExecutionStrategy</b> than before. And I hope, you are, too.Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-91070670380033204842013-11-10T14:37:00.000+01:002013-11-10T14:37:18.992+01:00log4javascript and ASP.NET Web Api<p><a href="http://log4javascript.org/" target="_blank">log4javascript</a> is a nice logging framework for JavaScript. With it you can log to the browser console (if supported by the browser), but also to an own window and even to the server via AJAX calls. For the latter, you need also something on the server which can handle the AJAX requests. Here I wanted to use ASP.NET Web Api. Since I didn’t find any documentation on this specific topic, I want to share my experiences here. <p>In general, the whole stuff is quite easy. On the client side you have to define the <strong>AjaxAppender</strong>:<pre class="brush: csharp;">var ajaxAppender = new log4javascript.AjaxAppender(serverUrl);
ajaxAppender.setLayout(new log4javascript.JsonLayout());
ajaxAppender.addHeader("Content-Type", "application/json; charset=utf-8");
</pre>I thought, with Web Api JSON would be the most natural data format. The more tricky line is the last one. Without it, the <b>Content-Type</b> header has the value <b>application/x-www-form-urlencoded</b>. This causes Web Api to use the <b>JQueryMvcFormUrlEncodedFormatter</b>. Unfortunately, this formatter cannot handle the JSON formatted data.<br />
After specifying the correct content type, Web Api uses the <b>JsonMediaTypeFormatter</b>. And everything is fine.<br />
<p>On the server side, I first had to define the structure of the log data:<pre class="brush: csharp;">public struct LogEntry
{
public string Logger;
public long Timestamp;
public string Level;
public string Url;
public string Message;
}
</pre>Since <strong>log4javascript</strong> can send more than one log entry in one AJAX call, my logging method gets an array of <strong>LogEntry</strong> instances. Additionally I needed to convert the timestamp value, since <strong>log4javascript</strong> sends it in milliseconds since 01-Jan-1970:<pre class="brush: csharp;">public void Write(LogEntry[] data)
{
if (data != null)
{
foreach (LogEntry entry in data)
{
DateTime timestampUtc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(entry.Timestamp);
DateTime timestampLocal = timestampUtc.ToLocalTime();
...
}
}
}
</pre>That’s it!</p>Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-13904918056698899442013-09-22T08:28:00.001+02:002013-09-22T08:30:06.458+02:00Registration-Free COM with ActiveX Controls<p>In my current project, I have beside other things, a form with an ActiveX control on it. Additionally, I am using registration free COM, meaning that the COM information is stored in a manifest file instead of the registry. <p>Everything worked fine, until I tried to create the form a second time. Also this worked without problems, but not in the Visual Studio debugger. Here I got the strange exception:<pre class="brush: plain;">System.NotSupportedException: Unable to get the window handle for the 'xxx' control. Windowless ActiveX controls are not supported.
at System.Windows.Forms.AxHost.EnsureWindowPresent()
at System.Windows.Forms.AxHost.InPlaceActivate()
at System.Windows.Forms.AxHost.TransitionUpTo(Int32 state)
at System.Windows.Forms.AxHost.CreateHandle()
at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
at System.Windows.Forms.AxHost.EndInit()
</pre><p>After hours of thinking, debugging, code stripping and so on (to be honest, mainly from a colleague of me), we found the solution: the used manifest was not complete. The manifest was created using <strong>mt.exe</strong> with the typelib of the control. This manifest looked like<pre class="brush: xml;"><file name="..." hashalg="SHA1">
<comClass clsid="..." tlbid="..." description="..." />
<typelib tlbid="..." version="..." helpdir="" />
</file>
</pre><p>When we compared this with the entries in the registry, we saw in the registry much more things. And also in the <a href="http://msdn.microsoft.com/library/windows/desktop/aa374219.aspx" target="_blank">assembly manifest documentation</a> are more attributes mentioned. Therefore we tried to add as much attributes to the manifest as possible (even if we did not understand every bit completely). And viola, now the error was gone!<br />
<p>In total, we added 4 attributes (in our case):<pre class="brush: xml;"><file name="..." hashalg="SHA1">
<comClass clsid="..." tlbid="..." description="..." threadingModel="..." progid="..." miscStatus="..." />
<typelib tlbid="..." version="..." helpdir="" flags="..." />
</file></pre><p>I hope this could help, if you have a similar issue.</p>Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-21922769386909595402013-09-18T20:54:00.000+02:002013-09-18T20:54:30.923+02:00AppDomains and user.configPreviously I had a problem with an application using different AppDomains. In one AppDomain I wrote some settings to an <b>user.config</b> file. And then I got in another AppDomain the following exception: <br />
<tt>System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize<br />
---> System.Configuration.ConfigurationErrorsException: Unrecognized configuration section userSettings. (C:\Users\uuuuuuuu\AppData\Local\cccccc\aaaaaaaaaaaaaa_Url_4v0elz3yo0gytsdhg5vusobffefqs0so\1.0.0.0\user.config line 3)</tt><br />
<br />
This was very strange since in this AppDomain I even didn’t use any <b>user.config</b>. After some hours of investigation, I found the problem. The <b>user.config</b> file will be written to <br />
<br />
<tt><Profile Directory>\<Company Name>\<App Domain>_<Evidence Type>_<Evidence Hash>\<Version>\user.config</tt><br />
<ul><li><strong><Profile Directory></strong>: %APPDATA% or %LOCALAPPDATA%</li>
<li><strong><Company Name></strong>: value of AssemblyCompanyAttribute, trimmed to 25 characters, invalid characters replaced by '_'</li>
<li><strong><App Domain></strong>: friendly name of the current AppDomain, trimmed to 25 characters, invalid characters replaced by '_'</li>
<li><strong><Evidence Type></strong> and <strong><Evidence Hash></strong>: some magic from AppDomain’s evidence</li>
<li><strong><Version></strong>: value of AssemblyVersionAttribute</li>
</ul>In my case, all these properties had the same value. Therefore the whole stuff got mixed up: <br />
<ul><li><strong>company name</strong>: ok this is by purpose the same</li>
<li><strong>version</strong>: I generated the version from the build number for all assemblies, but also this is not so uncommon</li>
<li><strong>evidence</strong>: I created the new AppDomains with <br />
<tt>AppDomain.CreateDomain(appDomainName, null, appDomainSetup);</tt><br />
The second parameter is the evidence for the new AppDomain. If it is null, the evidence from the current AppDomain will be taken. Also understandable.</li>
<li><strong>App domain</strong>: this was the sticky point. I used for the AppDomain’s name the full name of the main assembly. Since I used a pattern like Company.Application.Subsystem..., this name was simply too long. The first 25 characters were all the same...</li>
</ul>So the solution was quite easy: I just had to change the AppDomain’s name. But the trail to the solution took its time. Maybe this blog can accelerate your search a little bit. <br />
<br />
BTW: Finally I checked the source code of <a href="http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/Configuration/System/Configuration/ClientConfigPaths@cs/1305376/ClientConfigPaths@cs" target="_blank">System.Configuration.ClientConfigPaths.cs</a>. This helped me a lot to understand the problem.Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-31686146887119694312013-08-11T12:02:00.001+02:002013-08-11T12:02:44.064+02:00Problems with WSDL of WCF web services behind load balancerIf you have a WCF web service, you can get its WSDL by appending <strong>?wsdl</strong> to the URL: <pre>http://server/web/Service.svc?wsdl</pre>
Typically, the generated WSDL is not complete. The types are loaded separately from the server: <pre><xsd:import schemaLocation="http://server/web/Service.svc?xsd=xsd0" /></pre>
For the type import, the current machine is used. Normally this isn't a problem. But if you use a load balancer, you end up with the following requests: <pre>http://loadbalancer/web/Service.svc?wsdl
<xsd:import schemaLocation="http://node1/web/Service.svc?xsd=xsd0" /></pre>
This will not work, when <strong>node1</strong> is not accessible directly. <br />
Fortunately, you can force WCF to use the Loadbalancer also in the WSDL. You only have to add one line to the <strong>serviceBehavior</strong> in the <strong>Web.config</strong>: <pre class="brush: xml;"><behaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<useRequestHeadersForMetadataAddress />
...
</behavior>
</serviceBehaviors>
</behaviors></pre>
Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-65433491982635912642013-08-11T11:02:00.000+02:002013-08-11T11:02:07.750+02:00.net programs on 32 and/or 64 bit machinesGenerally, a .net program can run on a 32 bit machine as well as on a 64 bit machine. But sometimes it is necessary to run the program also on a 64 bit machine in 32 bit mode, the so-called WoW64. <br />
<blockquote><em>WoW64 stands for "Windows on 64-bit Windows", and it contains all the 32-bit binary files required for compatibility, which run on top of the 64 bit Windows. So, yeah, it looks like a double copy of everything in System32 (which despite the directory name, are actually 64-bit binaries).</em></blockquote>You will need WoW64 par example, if you want to call 32 bit ActiveX components. Visual Studio provides for this purpose the so-called platform target: <br />
<ul><li>x86<br />
32 bit application, runs either on Win32 or on Win64 in WoW64</li>
<li>x64<br />
64 bit application, runs only on Win64 (not in WoW64)</li>
<li>Any CPU<br />
runs on Win32 as 32 bit application and on Win64 as 64 bit application</li>
</ul>This info will be stored in the <strong>PE header</strong>. At application startup, Windows checks the settings and starts the application in the appropriate mode (or not). If you want to check later, for which platform the application was built, you can use the <strong>corflags</strong> tool in <strong>Visual Studio Command Prompt</strong>: <br />
<pre class="brush: plain;">> corflags MyApp.exe
Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 4.0.30319.1
Copyright (c) Microsoft Corporation. All rights reserved.
Version : v4.0.30319
CLR Header: 2.5
PE : PE32
CorFlags : 11
ILONLY : 1
32BIT : 1
Signed : 1</pre><br />
The interesting parts are <strong>PE</strong> and <strong>32BIT</strong>. The values are a little bit strange and hard to remember:<br />
<br />
<table border="0"><tbody>
<tr><td><strong>Platform target</strong></td><td><strong>PE</strong></td><td><strong>32BIT</strong></td></tr>
<tr><td>x86</td><td>PE32</td><td>1</td></tr>
<tr><td>x64</td><td>PE32+</td><td>0</td></tr>
<tr><td>Any CPU</td><td>PE32</td><td>0</td></tr>
</tbody></table><h3>References</h3><ul><li><a href="http://msdn.microsoft.com/library/ms164699.aspx" target="_blank">CorFlags.exe (CorFlags Conversion Tool)</a></li>
<li><a href="http://illuminatedcomputing.com/posts/2010/02/sorting-out-the-confusion-32-vs-64-bit-clr-vs-native-cs-vs-cpp/" target="_blank">Sorting Out the Confusion: 32- vs. 64-Bit, CLR vs. Native, C# vs. C++</a></li>
</ul>Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-73342627521754567702013-08-10T11:19:00.000+02:002013-08-10T11:19:29.759+02:00Problem with asynchronous HttpClient methodsRecently, I wrote a client application which should send some log messages to a server. Since it was only for statistics, the log didn’t have the highest requirements on reliability. Additionally, it shouldn’t block my application. Therefore I decided to send the message asynchronously, and in case of an error only to write something to the local log file. I came up with<br />
<br />
<pre class="brush: csharp">static void LogMessage(string message)
{
Uri baseAddress = new Uri("http://localhost/");
string requestUri = "uri";
using (HttpClient client = new HttpClient { BaseAddress = baseAddress })
{
client.PostAsJsonAsync(requestUri, message, cancellationToken).ContinueWith(task =>
{
if (task.IsFaulted)
Console.WriteLine(“Failed: “ + task.Exception);
else if (task.IsCanceled)
Console.WriteLine ("Canceled");
else
{
HttpResponseMessage response = task.Result;
if (response.IsSuccessStatusCode)
Console.WriteLine("Succeeded");
else
response.Content.ReadAsStringAsync().ContinueWith(task2 => Console.WriteLine(“Failed with status " + response.StatusCode));
}
});
}
}
</pre>
<br />
This code should send the message asynchronously (<strong>PostAsJsonAsync</strong>). And afterwards it should check, if the sending was successfully or not (<strong>ContinueWith</strong>). My expectation was to see an error, since there is nothing is listening on the specified address. But I didn’t see anything. Moreover, it even didn’t send any requests. Even for my requirements, this was not enough. <br />
<br />
After some research, I added trace switches to my config file:<br />
<br />
<pre class="brush: xml"><system.diagnostics>
<switches>
<add name="System.Net" value="Verbose"/>
<add name="System.Net.Http" value="Verbose"/>
<add name="System.Net.HttpListener" value="Verbose"/>
<add name="System.Net.Sockets" value="Verbose"/>
<add name="System.Net.Cache" value="Verbose"/>
</switches>
</system.diagnostics>
</pre>
<br />
With it, one of the last lines of my debug output was<br />
<br />
<pre>System.Net Error: 0 : [0864] Exception in HttpWebRequest#54246671:: - The request was aborted: The request was canceled..
</pre>
<br />
This led me to the evil: it was the disposing of <strong>HttpClient</strong> too early. At the end of the <strong>using</strong> block the client will be disposed. But at this time, the message has not been sent. This happens, since I do something asynchronous inside the <strong>using</strong> block without waiting for its end.<br />
<br />
The solution to this problem is to reverse the order of using and asynchronous: if I start the using in an asynchronous way, everything is fine:<br />
<br />
<pre class="brush:csharp">static void LogMessage(string message)
{
Uri baseAddress = new Uri("http://localhost/");
string requestUri = "uri";
new TaskFactory().StartNew(() =>
{
using (HttpClient client = new HttpClient { BaseAddress = baseAddress })
{
Console.WriteLine("Sending message");
HttpResponseMessage response = client.PostAsJsonAsync(requestUri, message).Result;
Console.WriteLine("Evaluating response");
if (response.IsSuccessStatusCode)
Console.WriteLine("Succeeded");
else
Console.WriteLine("Failed with status " + response.StatusCode);
}
});
}
</pre>
<br />
Here I start a new task, which does inside the <strong>using</strong> / <strong>Dispose</strong> stuff. And the task is finished only after the <strong>Dispose</strong>.<br />
<br />
This took me to the next stage: what about the <strong>async</strong> / <strong>await</strong> pattern from .net 4.5? The implementation is quite similar to the one above - the main difference is that the method now has to return a <strong>Task</strong>.<br />
<br />
<pre class="brush:csharp">static <span style="color: red;">async Task</span> LogMessage (string message)
{
Uri baseAddress = new Uri("http://localhost/");
string requestUri = "uri";
using (HttpClient client = new HttpClient { BaseAddress = baseAddress })
{
Console.WriteLine("Sending message");
HttpResponseMessage response = <span style="color: red;">await</span> client.PostAsJsonAsync(requestUri, message);
Console.WriteLine("Evaluating response");
if (response.IsSuccessStatusCode)
Console.WriteLine("Succeeded");
else
Console.WriteLine("Failed with status " + response.StatusCode);
}
}
</pre>
<br />
Also this implementation starts a new thread for the response message handling. But it does it only if really needed. And it does it as late as possible. <br />
<br />
A little more sophisticated logging shows some details (the 2nd column is the thread number). The implementation with an explicit Task calls LogMessage on the main thread 9. Afterwards in continues immediately on the same thread. Approx. 20 ms later the new thread 12 starts with the HTTP handling:<br />
<br />
<pre class="brush:text">21:28:42.524 9 CallMethod Calling LogMessageWithTask
21:28:42.526 9 CallMethod Continuing after LogMessageWithTask
21:28:42.545 12 LogMessageWithTask Sending message
21:28:45.682 12 LogMessageWithTask Evaluating response
21:28:45.682 12 LogMessageWithTask Failed with status NotFound
</pre>
<br />
With <strong>async</strong> / <strong>await</strong> it is a little bit different: also the request will be sent on the main thread. The response handling will be done later also in a second thread: <br />
<br />
<pre class="brush:text">21:28:51.638 9 CallMethod Calling LogMessageAsyncAwait
21:28:51.666 9 LogMessageAsyncAwait Sending message
21:28:51.701 9 CallMethod Continuing after LogMessageAsyncAwait
21:28:52.144 16 LogMessageAsyncAwait Evaluating response
21:28:52.144 16 LogMessageAsyncAwait Failed with status NotFound
</pre>
<br />
However, the coding is more precise. And the request will be sent without the delay for creating the new <strong>Task</strong>.<br />
<br />
<hr />
<br />
You can find the source code at GitHub: <a href="https://github.com/Ritzlgrmft/HttpClientDispose">https://github.com/Ritzlgrmft/HttpClientDispose</a>.Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-91034055919343544632013-06-20T00:23:00.000+02:002013-06-20T00:23:19.786+02:00AJAX calls to different servers (CORS)Developing modern HTML applications, sometimes you have the need to send an AJAX request data to another server. Unfortunately, this could be a security issue. Therefore all browsers implement the <a href="http://en.wikipedia.org/wiki/Same_origin_policy" target="_blank">Same origin policy</a>, which prevents such calls.<br />
But what, if you really need it? The rescue is <a href="http://en.wikipedia.org/wiki/Cross-origin_resource_sharing" target="_blank">Cross-origin resource sharing (CORS)</a>. The principle is quite easy: the browser sends with the AJAX request an additional HTTP header:<br />
Origin: http://www.foo.com<br />
The server can analyze the header. If it decides to fulfill the request, it adds another header:<br />
<pre class="brush: text">Access-Control-Allow-Origin: http://www.foo.com
</pre>
If the server decides to trust all clients, it can also return <br />
<pre class="brush: text">Access-Control-Allow-Origin: *
</pre>
But if you send the AJAX request from a page with origin <b>http://www.foo.com</b>, while the server replies with <b>http://www.bar.com</b>, you cannot read the response.<br />
<h3>
Browser support</h3>
All major browsers support CORS with <a href="http://www.w3.org/TR/XMLHttpRequest/" target="_blank">XMLHttpRequest</a>. All but IE8 or IE9. These IE versions use a slightly different approach. When you want CORS, you have to use another object instead: <a href="http://msdn.microsoft.com/en-us/library/ie/cc288060.aspx" target="_blank">XDomainRequest</a>. Fortunately at least its interface is similar to <strong>XMLHttpRequest</strong>. <br />
<h3>
JQuery</h3>
JQuery uses for AJAX calls always <strong>XMLHttpRequest</strong>. The request to use <strong>XDomainRequest</strong> when needed was <a href="http://bugs.jquery.com/ticket/8283" target="_blank">rejected</a>. Instead it is recommended to use a JQuery plugin. For this purpose I found 2 implementations:<br />
<ul>
<li><a href="https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest" target="_blank">jQuery.XDomainRequest</a></li>
<li><a href="https://github.com/dkastner/jquery.iecors" target="_blank">jQuery.iecors</a></li>
</ul>
Both worked for me, but with <strong>jQuery.iecors</strong> I had problems receiving errors. At least in my tests the error function was not called. Therefore I finally decided to use <strong>jQuery.XDomainRequest</strong>.<br />
<h3>
CORS and ASP.NET Web Api</h3>
For supporting CORS with ASP.NET Web Api, you need to add the <strong>Access-Control-Allow-Origin </strong>header to the response. One way is to implement a custom message handler for this purpose. <a href="http://blogs.msdn.com/b/carlosfigueira/archive/2012/02/20/implementing-cors-support-in-asp-net-web-apis.aspx" target="_blank">Carlos Figueira</a> blogged a good description, how to do this.<br />
<br />Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0tag:blogger.com,1999:blog-4948552110773697689.post-67136270472625305562013-06-18T06:25:00.000+02:002013-07-08T18:38:24.452+02:00OWIN with static files, exception handling and loggingAs I wrote already in <a href="http://ritzlgrmft.blogspot.de/2013/03/self-host-aspnet-web-api-and-signalr.html" target="_blank">Self-host ASP.NET Web API and SignalR together</a>, the OWIN configuration is done in <strong>Startup.Configuration()</strong>:<br />
<pre class="brush: csharp">public void Configuration(IAppBuilder app)
{
// Configure WebApi
var config = new HttpConfiguration();
config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
app.UseWebApi(config);
// Configure SignalR
app.MapHubs();
}
</pre>It looks, as if there are some features get activated with <b>app.UseXXX()</b> (or <b>app.MapHubs()</b>, respectively). But this is not completely true. When we look into the implementation of these "feature activating methods", they finally call<br />
<pre class="brush: csharp">public IAppBuilder Use(object middleware, params object[] args)
{
this._middleware.Add(AppBuilder.ToMiddlewareFactory(middleware, args));
return (IAppBuilder) this;
}
</pre>This method adds the features to a list. During the request processing, every feature in this list will be checked, if it can handle the request. Therefore the order of the "feature activating methods" can be important. Not in the example above, since WebApi and SignalR do not compete for the same requests.<br />
<h3>Microsoft.Owin.Diagnostics</h3>The package <a href="http://nuget.org/packages/Microsoft.Owin.Diagnostics/" target="_blank">Microsoft.Owin.Diagnostics</a> contains one useful feature catching and displaying exceptions. For sure this shouldn't happen, but when it would be nice to know about. But as always you should consider to use it only during development.<br />
<br />
To switch it on, simply add the following line at the beginning of <strong>Startup.Configuration()</strong>:<br />
<pre class="brush: csharp">app.UseShowExceptions();
</pre><br />
Another feature in <b>Microsoft.Owin.Diagnostics</b> is <br />
<pre class="brush: csharp">app.UseTestPage();
</pre>This displays the message <b>Welcome to Katana</b> to the client. You should place it at the very end of <b>Configuration.Startup()</b>. Otherwise your other features wouldn't never reached.<br />
<br />
But anyway, this feature is useful only in hello world status. Later I would prefer to get HTTP 404 instead of this message.<br />
<h3>Microsoft.Owin.StaticFiles</h3>Like most of the other OWIN packages, also <strong><a href="http://nuget.org/packages/Microsoft.Owin.StaticFiles/" target="_blank">Microsoft.Owin.StaticFiles</a></strong> is in prerelease status. But this package is special, you even cannot find it in <strong>NuGet</strong>. To install it, you need to enter the following command in the <strong>Package Manager Console</strong>:<br />
<pre class="brush: text">Install-Package Microsoft.Owin.StaticFiles -Version 0.20-alpha-20220-88 -Pre
</pre>But probably the package is hidden since it doesn't work really. It has problems when you request more than one file in parallel. The solution is to use one of the nightly Katana builds (e.g. <b>0.24.0-pre-20624-416</b>). Probably this is even more alpha than the hidden version. But is works better. Obviously there was some improvement between version <b>0.20</b> and <b>0.24</b>.<br />
You can get the nightly builds from a separate feed: <a href="http://www.myget.org/f/Katana" target="_blank">http://www.myget.org/f/Katana</a>.<br />
After adding the package, just add one line to <b>Startup.Configuration()</b>:<br />
<pre class="brush: csharp">app.UseStaticFiles("StaticFiles");
</pre>The parameter specifies, in which directory the static files will be searched. Since I named it <strong>StaticFiles</strong>, you have to add a folder with this name to your project. And for every file you add to this folder you have to set in its properties that it will be copied to the output directory:<br />
<div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIzl4uCZ6kp5XM07Ww07lU4lP4vnlMxiwT8TABLDmV03onXaxdgV2MJRh-xZRUp07QwYKnakzNFngvIKROEVE_XhA44_PDqA439cnkeD6R-FLz8IXpIkBLclgr2ijQ4RHf_-DDc3phTLo/s1600/FileProperties.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIzl4uCZ6kp5XM07Ww07lU4lP4vnlMxiwT8TABLDmV03onXaxdgV2MJRh-xZRUp07QwYKnakzNFngvIKROEVE_XhA44_PDqA439cnkeD6R-FLz8IXpIkBLclgr2ijQ4RHf_-DDc3phTLo/s1600/FileProperties.PNG" /></a></div><br />
When you start the project, you can fire up the browser and enter <a href="http://localhost:8080/test.htm">http://localhost:8080/test.htm</a> (without specifying the <strong>StaticFiles</strong> folder), and you get simply the page back.<br />
<h3>Logging OWIN requests</h3>Sometimes it would be interesting to see the incoming requests in a trace. This can be achieved with a custom feature. The constructor is quite simple. It just stores the reference to the next feature:<br />
<pre class="brush: csharp">private readonly Func<IDictionary<string, object>, Task> _next;
public Logger(Func<IDictionary<string, object>, Task> next)
{
if (next == null)
throw new ArgumentNullException("next");
_next = next;
}
</pre>The implementation isn't really complicated, too:<br />
<pre class="brush: csharp">public Task Invoke(IDictionary<string, object> environment)
{
string method = GetValueFromEnvironment(environment, OwinConstants.RequestMethod);
string path = GetValueFromEnvironment(environment, OwinConstants.RequestPath);
Console.WriteLine("Entry\t{0}\t{1}", method, path);
Stopwatch stopWatch = Stopwatch.StartNew();
return _next(environment).ContinueWith(t =>
{
Console.WriteLine("Exit\t{0}\t{1}\t{2}\t{3}\t{4}", method, path, stopWatch.ElapsedMilliseconds,
GetValueFromEnvironment(environment, OwinConstants.ResponseStatusCode),
GetValueFromEnvironment(environment, OwinConstants.ResponseReasonPhrase));
return t;
});
}
</pre>First, it prints some data of the current request. The more interesting part is, that it then calls the succeeding features (<b>return _next(environment)</b>). And when the succeeding features were evaluated, it finally (<b>ContinueWith</b>) prints some response data. I added here also <b>method</b> and <b>path</b>, since otherwise it were difficult to find the corresponding entries. Maybe it would be even better to use some kind of unique id for this purpose. But in my projects, <b>method</b> and <b>path</b> are enough.<br />
<b>GetValueFromEnvironment</b> is only a little helper, since in some cases the <b>environment </b>dictionary does not contains all values:<br />
<pre class="brush: csharp">private static string GetValueFromEnvironment(IDictionary<string, object> environment, string key)
{
object value;
environment.TryGetValue(key, out value);
return Convert.ToString(value, CultureInfo.InvariantCulture);
}
</pre>Since the <b>Logger</b> traces the beginning and the end of the processing, it should be activated quite at the beginning of <b>Startup.Configuration()</b>:<br />
<pre class="brush: csharp">app.Use(typeof(Logger));
</pre><h3>Logging the Request Body</h3>With POST requests, it can be very handy to log also the request body. For this, you have only to extend the <b>Invoke</b> method a little bit:<br />
<pre class="brush: csharp">string requestBody;
Stream stream = (Stream)environment[OwinConstants.RequestBody];
using (StreamReader sr = new StreamReader(stream))
{
requestBody = sr.ReadToEnd();
}
environment[OwinConstants.RequestBody] = new MemoryStream(Encoding.UTF8.GetBytes(requestBody));
</pre>The access to the request body is provided by a <b>Stream</b>. The only caveat with this stream is that it is not seekable. That means you can read it only once. And maybe the simple logging will not be enough for your requirements. Sometimes you will also process it afterwards...<br />
Fortunately, this is no big issue: just replace the old stream with a new <b>MemoryStream</b>. For sure, this is not good idea with big request bodies. In such a case you will need a more sophisticated solution. But normally, it should be good enough. Moreover, you can use it only during development. In production you can disable it by configuration, par example.<br />
<h3>Logging SignalR</h3>With the <b>Logger</b> from above, you get a nice logging of the several SignalR requests (when it uses <b>LongPolling</b> instead of <b>WebSockets</b>):<br />
<pre class="brush: text">10:51:18,181 11 Entry GET /signalr/negotiate
10:51:18,263 8 Exit GET /signalr/negotiate 82
10:51:18,271 11 Entry GET /signalr/ping
10:51:18,275 8 Exit GET /signalr/ping 4
10:51:18,540 11 Entry GET /signalr/connect
10:53:08,806 14 Exit GET /signalr/connect 110260
10:53:08,826 11 Entry GET /signalr/poll
10:54:58,960 15 Exit GET /signalr/poll 110128
10:54:58,969 11 Entry GET /signalr/poll
10:56:49,136 12 Exit GET /signalr/poll 110161
</pre>The used <b>Logger</b> prints also timestamp and thread id (in the first 2 columns). It is easily to see, how <b>SignalR</b> waits for 110 seconds for an answer from the server (a notification). When it doesn't get one, it simply sends the next request. <br />
You can also see that all requests (at least in this example) are handled by the same thread (11). But the response is created by other threads (8, 14, 15 and 12).<br />
<h3>Summary</h3>It is quite easy to add additional features to an OWIN host. And it is also not too hard to implement own features. Drawbacks of the whole stuff are (hopefully only at the moment):<br />
<ul><li>the beta status of some packages</li>
<li>the lack of documentation</li>
</ul>But for a real developer, the best documentation is the code, anyway.<br />
<hr />You can find the source code at GitHub: <a href="https://github.com/Ritzlgrmft/OwinConfiguration" target="_blank">https://github.com/Ritzlgrmft/OwinConfiguration</a>.Markus Wagner's Blog about .net and mobile Developmenthttp://www.blogger.com/profile/15030048659432680447noreply@blogger.com0