Integrate ASP.NET 5 and Webpack with Hot Module Replacement plugin

Every app runs in at least two environments: production and development.

This post is about the separation of the environment configs using Webpack and ASP.NET 5.

Webpack

Add two configs:

  • webpack.config.dev.js
  • webpack.config.prod.js

webpack.config.dev.js contains Hot Module Replacement in plugins section:

plugins: [
  new webpack.HotModuleReplacementPlugin()
]

In webpack.config.prod.js plugins section contains ExtractTextPlugin and UglifyJsPlugin:

plugins: [
  ...

  new webpack.optimize.UglifyJsPlugin({
  compressor: {
    warnings: false
  }
  }),
  new ExtractTextPlugin('styles.css')
]

Evironment Tag Helpers

Use Evironment Tag Helpers to switch between development and production environment in Layout.cshtml add:

@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"

...

<environment names="Production">
  <link rel="stylesheet" href="/styles.css">
</environment>

...

<environment names="Development">
  <script src="http://localhost:3000/bundle.js"></script>
</environment>
<environment names="Production">
  <script src="/bundle.js"></script>
</environment>
```html

in `project.json` add:

```json
"dependencies": {
  "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final"
}

Development

Run webpack dev server:

npm i
npm run build

Run ASP.NET project:

dnx --project src\AspNet5DemoApp dev

Production

Add property postrestore project.json for install npm modules from package.json

"scripts": {
  "postrestore": ["cd ../.. && npm i && cd src/AspNet5DemoApp"]
}

In package.json add property postinstall to scripts section:

"scripts": {
  "build": "webpack",
  "postinstall": "if [ \"$NODE_ENV\" = production ]; then npm run build; fi"
}

postinstall command run after the package is uninstalled if environment is production (NODE_ENV=production).

Deploying asp.net 5 on heroku

Deprecated

New version: Deploying ASP.NET Core on heroku


jincod/dotnet-buildpack forked from: heroku/dotnet-buildpack

heroku buildpacks:set https://github.com/jincod/dotnet-buildpack

AspNet5 Demo App

git clone https://github.com/jincod/AspNet5DemoApp.git
git push origin master

Deploy to Heroku

Click the button below to set up this sample app on Heroku:

Deploy

Knockout mapping hacks

Problem

Some fields defined in viewModel but missed in data will be lost after using ko.mapping.

View model definition

var viewModel = {
  id: ko.observable(),
  name: ko.observable("name"),
  items: ko.observableArray()
};
var data = {
    id: 1,
    items: [{text: "text", value: "value"}]
};
ko.mapping.fromJS(data, {}, viewModel);
console.log(ko.mapping.toJSON(viewModel));

Result

{"id":1,"items":[{"text":"text","value":"value"}]}

‘name’ field was missing.

var data = {
    id: 1,
    items: [{text: "text", value: "value"}]
};
ko.mapping.fromJS(data, {include: Object.keys(viewModel)}, viewModel);
console.log(ko.mapping.toJSON(viewModel));

Result

{"id":1,"name":"name","items":[{"text":"text","value":"value"}]}

Get correct viewModel after mapping.

Solution

var maping = {
  include: Object.keys(viewModel)
};
ko.mapping.fromJS(data, mapping, viewModel);

https://jsfiddle.net/cvdex801/

Different convert MailMessage to MemoryStream in .NET4 and .NET4.5

Method:

private static MemoryStream ConvertMailMessageToMemoryStream(MailMessage message)
{
    Assembly assembly = typeof (SmtpClient).Assembly;
    Type mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
    var fileStream = new MemoryStream();
    ConstructorInfo mailWriterContructor =
        mailWriterType
            .GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] {typeof (Stream)}, null);
    object mailWriter = mailWriterContructor.Invoke(new object[] {fileStream});
    MethodInfo sendMethod =
        typeof (MailMessage)
            .GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);
    sendMethod
        //.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] {mailWriter, true}, null);
        // for .net 4.5 user this:
        .Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] {mailWriter, true, true}, null);
    MethodInfo closeMethod =
        mailWriter
            .GetType()
            .GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
    closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] {}, null);
    return fileStream;
}

.NET4:

sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] {mailWriter, true}, null);

.NET4.5

sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] {mailWriter, true, true}, null);

Different:

-new[] {mailWriter, true}
+new[] {mailWriter, true, true}

Express.js route builder from controllers

App structure:

.
├── index.coffee
└── server
    ├── controllers
        └── api.coffee
        └── user.coffee
    └── router.coffee
    └── app.coffee

api.coffee:

express = require 'express'

router = express.Router()

test = (req, res, next) -> res.sendStatus 200
add = (req, res, next) -> res.sendStatus 200

router.get '/test', test
router.post '/add', add

module.exports = router

Read all route info from controllers and build app routes:

Example source