Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Hosted-services / Azure

SPA^2 using ASP.Net Core 1.1 + Angular 4.0 - part 9

5.00/5 (6 votes)
19 Apr 2017CPOL22 min read 26.5K   307  
Publishing the ASP.Net Core 1.1 / Angular 4 SPA to Azure and external IIS hosts. Also covering code cleanup, optimization, bundling and minification. Gulp, Grunt, Webpack and some architecture and development philosophy.

Source

if the above source is unavailable, you can also get the latest source from GitHub here.

Introduction

The aim of this series of articles has been to create a Single Page Application or SPA using ASP.Net Core and Angular 4, but instead of ignoring tag helpers, razor or other the other great aspects of ASP.Net Core - to make active use of these in the client side with Angular 4.

The parts 1, 2, 3 covered basic project setup, then the 4th part token authentication using OpenIdDict, in the 5th we added smarter validation, then in the 6th used NSwag to create Swagger docs and auto-generate code. The last two part 7 & part 8 covered publishing locally using VS 2015 and VS 2017 respectively.

Finally in this last part I'll cover some of the rationale and decisions behind the design, we'll do some optimization, see how to do bundling and minification, and how we could add in LESS or SASS style sheets, then last of all how to publish to external web hosts and to Azure.

Optimizing the build - why? what is it? how?

Why optimize the build at all? What does this mean?

I'm assuming that optimizing here is defined as making (1) our development cycles (edit, test, deploy), (2) deployment (publishing time + size of published files) and (3) user experience (page load time, page sizes) are all tweaked as well as is practical. This last part is important, "as well as is practical", since too much optimizing is wasteful of development time (too little benefit for too much effort) on the other hand too little optimizing and your development time can be wasted when users are dissatisfied with your site, or your development is slowed down as the site takes too long to publish.

Fortunately many of the fixes to one of these three issues will also help the other two.

One of the biggest causes of slow deployments, and slow page loads can be the sheer number and size of the files making up our application.

Do you need it? The first area to fix will be to try and remove files we don't need. This might seem a little basic, but I've found it easy for people to add a library in case they need it, only to find later it was not used at all. If you are  working in a team, make it a habit to talk over with a team member when you are thinking of adding a new library. Look at alternative libraries, (can you use one library that does two jobs?) or can you find a smaller library, or do you need it at all?

Can you make it smaller? The next area to look at is bundling and minification. Bundling is combining many smaller files together as one, since there are a limited number of requests and connections between a given browser and your server, if you can minimize the number of these, even if the sum of say three files 1k+1k+1K = 3k were not changed, the overheads of each request for the 3 files separately versus 1 combined file will mean the site will usually appear to load faster to the user. The other aspect of combining the files is that storage space will be a little smaller (a 1k file can take 4k or 8k units of space to store in your file system), a single bundled file will save some space there too.

The other aspect of making files smaller is to use "minification". This is a term applied to various techniques that reduce a given files' size. Typically there's a lot of white space (spaces, carriage returns, tabs) and longer human readable function names and variable names that can be reduced. By using just a single character instead of a longer word as a variable name and removing this whitespace, we can make our files much smaller. Minification (and bundling) can be applied to .js JavaScript and .css style sheet files.

By convention a minified file is renamed to have a .min in the filename. For example site.css would become site.min.css, or systemjs.config.js becomes systemjs.config.min.js and usually left beside the non-minified file. In the case of bundling, many minified files can be combined together into one file, in which case the destination of the bundled file is usually a common script or style sheet folder.

Usually during development, the original file is used for debug builds while the minified version is used for release builds or publishing to a production environment.

There is already a mechanism in place to handle the different file names and deliver the appropriate version when needed in ASP.Net Core. You'll see an example of this in _layout.cshtml

HTML
<environment names="Development">
          ...
</environment>
<environment names="Staging,Production">
          ...
</environment>

Note: This is just another benefit of this technique of creating a SPA, in actually using ASP.Net Core as more than a file server, since using plain .html files in our SPA would not give us the ability to use the built-in environment tag helpers, as shown above.

Users of the earlier ASP.Net MVC 4.x framework will have been used to a Bundles.cs class that handled bundling and minification. In ASP.Net Core you need to have some other mechanism to do this. There are a number of alternatives, including Gulp, Grunt and WebPack or a simple and effective alternative, one of the amazing developer's at Microsoft, Mads Kristensen, has created a “BundlerMinifier” that is available as an addin or Visual Studio. Mads’ “BundlerMinifier” does in-place minification and bundling, is incredibly easy to use, as it is virtually automatic. It has the advantage of allowing you to easily move to Gulp, if the need arises, and still keep things as simple as possible.

Using Mads Kristensen's “BundlerMinifier”

Mads Kristensen's "Bundler Minifier" add in is available for both VS 2015 and VS 2017. If you haevn't installed it, go to the tools menu, then select Extensions and Updates:

Image 1

Select "Bundler & Minifier" as shown below, then click Download. You'll likely need to restart Visual Studio to have this enabled, however a quick word on Extensions; While adding Mads Kristensen's BundlerMinifier, do add Web Essentials. It's a fantastic collection of very useful tools for Visual Studio:

Image 2

Once you start the installation of Web Essentials it will automaticalyl load the component parts, as below:

Image 3

Don't worry too much about CPU use, these are very well written addins; I have found very good results even on moderately powered PCs.

Once your Bundler & Minifier add in has been installed, right click a CSS file or JavaScript file you would like minified,

Image 4

Click minify file, and then the file will be added to the bundleconfig.json as shown:

JavaScript
[
  {
    "outputFileName": "wwwroot/css/site.min.css",
    "inputFiles": [
      "wwwroot/css/site.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/site.min.js",
    "inputFiles": [
      "wwwroot/js/site.js"
    ],
    "minify": {
      "enabled": true,
      "renameLocals": true
    }
  },
  {
    "outputFileName": "wwwroot/systemjs.config.min.js",
    "inputFiles": [
      "wwwroot/systemjs.config.js"
    ]
  }
]

A quick look in Windows Explorer shows we have potentially saved around 800 bytes, going from 1976 bytes to 1175 bytes.

Image 5

 

To make this minified file active, (and not just sit there doing nothing) you now need to edit _layout.chtml to alter the following (abbreviated version shown) from this:

HTML
<environment names="Development">
          ...
    <script src="~/systemjs.config.js"></script>
          ...
</environment>
<environment names="Staging,Production">
          ...
    <script src="~/systemjs.config.js"></script>
          ...
</environment>

To this:

HTML
<environment names="Development">
          ...
    <script src="~/systemjs.config.js"></script>
          ...
</environment>
<environment names="Staging,Production">
          ...
    <script src="~/systemjs.config.min.js"></script>
          ...
</environment>

Sometimes minification can break a file, when there’s a dependency into another file that is missed, or assumed to be not needed. It’s wise therefore not to minify too many files at once, but do or two at a time and see if everything still works. You can slip the minified version into your development section, try it out, and then if it works, add the .min into the staging/production section and leave the development section still running the original version.

So, next a quick look through the _Layout.cshtml to see if there are other files we can also minify, and then we’ll add some of these into a bundle to demonstrate the concept. First in the head section, there is toastr.css which is not minified:

HTML
<environment names="Staging,Production">
     ...
    <link rel="stylesheet" href="~/node_modules/ngx-toastr/toastr.css" />
</environment>

This comes from an NPM module, in the /node_modules folder. Check to see if the package is distributed with minified version, (and there is none) so we’ll now add this one into the to-be-minified files.

A quick note about the /node_modules folder

As an aside, by default VS 2017 shows the /node_modules folder and contents, since they are present in the solution space, yet by default they won’t get committed to the GIT repo since our standard .git ignore file happens to have an entry to exclude the contents of the /node_modules folder.

If you do exclude the /node_modules folder (right click and exclude) from the project, you will make publishing difficult as it hides the folder from publishing.  In some frameworks or applications, this might be desirable, if say you go to the effort of copying the (many) required files from the /node_modules folder into the /wwwroot folder. But we’re not going to do that, for a small to moderate SPA application, IMO this is too much effort and too much maintenance. (Note: web pack or gulp can do the job, if you need to do this, but more on these later, as they also amount to work).

Let’s get back to minifying the toastr.css file.

Open up the /node_modules folder in the solution explorer window of Visual Studio. Find the ngx-toast folder, then in turn the toastr.css file

Image 6

Right click the file, click “Bundler & Minifier” then “Minify File”, now our bundleconfig.json file will become:

JavaScript
[
  {
    "outputFileName": "wwwroot/css/site.min.css",
    "inputFiles": [
      "wwwroot/css/site.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/site.min.js",
    "inputFiles": [
      "wwwroot/js/site.js"
    ],
    "minify": {
      "enabled": true,
      "renameLocals": true
    }
  },
  {
    "outputFileName": "wwwroot/systemjs.config.min.js",
    "inputFiles": [
      "wwwroot/systemjs.config.js"
    ]
  },
  {
    "outputFileName": "node_modules/ngx-toastr/toastr.min.css",
    "inputFiles": [
      "node_modules/ngx-toastr/toastr.css"
    ]
  }
]

Notice the default option is to minify a given file and pop it right beside the original. Often this is a great choice, but suppose we want to have the option of putting this with our other styles, so we can see the files in one place, and say bundle them later:

Change this section from:

JavaScript
{
  "outputFileName": "node_modules/ngx-toastr/toastr.min.css",
  "inputFiles": [
    "node_modules/ngx-toastr/toastr.css"
  ]
}

To:

JavaScript
{
  "outputFileName": "wwwroot/css/      toastr.min.css",
  "inputFiles": [
    "node_modules/ngx-toastr/toastr.css"
  ]
}

Soon after saving the change to bundlerconfig.json the /app/css stylesheet folder:

Image 7

 

Gets a new addition:

Image 8

It doesn’t take too much imagination to see you can do this bundling a few ways,

One, I think the simplest is this:

JavaScript
{
  "outputFileName": "wwwroot/css/site.min.css",
  "inputFiles": [
    "wwwroot/css/site.css",
    "node_modules/ngx-toastr/toastr.css"
  ]
},

And not even bother minifying the toastr.css file on its own. So remove the last section, that creates the toastr.min.css and keep this:

JavaScript
[
  {
    "outputFileName": "wwwroot/css/site.min.css",
    "inputFiles": [
      "wwwroot/css/site.css",
      "node_modules/ngx-toastr/toastr.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/site.min.js",
    "inputFiles": [
      "wwwroot/js/site.js"
    ],
    "minify": {
      "enabled": true,
      "renameLocals": true
    }
  },
  {
    "outputFileName": "wwwroot/systemjs.config.min.js",
    "inputFiles": [
      "wwwroot/systemjs.config.js"
    ]
  }
]

Our original _layout.cshtml has the bootstrap.css file as well, for development, but uses a CDN (or content delivery network) with a fallback for staging and production.

HTML
<environment names="Development">
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
    <link rel="stylesheet" href="~/node_modules/ngx-toastr/toastr.css" />
</environment>
<environment names="Staging,Production">
    <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css"
          asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
          asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
    <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>

For the sake of the exercise let’s add bootstrap style sheet in as well. Edit bundleconfig.json (top section only shown) to add in bootstrap.css

JavaScript
{

  "outputFileName": "wwwroot/css/site.min.css",

  "inputFiles": [

    "wwwroot/css/site.css",

    "wwwroot//lib/bootstrap/dist/css/bootstrap.css",

    "node_modules/ngx-toastr/toastr.css"

  ]

},

Then update _layout.cshtml to:

HTML
<environment names="Development">
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
    <link rel="stylesheet" href="~/node_modules/ngx-toastr/toastr.css" />
</environment>
<environment names="Staging,Production">
    <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>

The three files: bootstrap.css at 150k, style.css at 2k, and toastr.css at 7k, when minified and then bundled become a single file of 125k.

For sake of space, I’ll leave the step by step minification and bundling process as an exercise to you, however this is my version optimized for me to use commuting (with a minimum of CDN) and where I host the files myself. For instance you can easily add files such as system.config.js

Image 9

Here’s the updated bundleconfig.json file:

JavaScript
[
  {
    "outputFileName": "wwwroot/css/site.min.css",
    "inputFiles": [
      "wwwroot/css/site.css",
      "wwwroot/lib/bootstrap/dist/css/bootstrap.css",
      "node_modules/ngx-toastr/toastr.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/site.min.js",
    "inputFiles": [
      "wwwroot/lib/jquery/dist/jquery.js",
      "wwwroot/bootstrap/dist/js/bootstrap.js",
      "wwwroot/js/site.js",
      "node_modules/core-js/client/shim.min.js",
      "node_modules/zone.js/dist/zone.js",
      "node_modules/systemjs/dist/system.src.js",
      "wwwroot/systemjs.config.js"
    ],
    "minify": {
      "enabled": true,
      "renameLocals": true
    }
  }
]

And here’s the updated scripts from the body section of _layout.cshtml after minification:

HTML
<environment names="Development">
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    <!-- Polyfill(s) for older browsers -->
    <script src="~/node_modules/core-js/client/shim.min.js"></script>
    <script src="~/node_modules/zone.js/dist/zone.js"></script>
    <script src="~/node_modules/systemjs/dist/system.src.js"></script>
    <script src="~/systemjs.config.js"></script>
    <script>
        System.import('app').catch(function (err) { console.error(err); });
    </script>
</environment>
<environment names="Staging,Production">
    <script src="~/js/site.min.js" asp-append-version="true"></script>
    <script>
        System.import('app').catch(function (err) { console.error(err); });
    </script>
</environment>

Still working:

Image 10

What about Gulp or Grunt?

Gulp and Grunt can perform a number of roles including minification and bundling, as mentioned earlier, they can help you create CSS style sheets using LESS or SASS sources, and they can also help you do simple file copy tasks. 

So, which one? There’s plenty of discussion, but https://www.keycdn.com/blog/gulp-vs-grunt/ compares them both and Gulp seems to win in simplicity, versatility, ease of use and speed.

Personally, I think if you can hold off using either Gulp or Grunt, but stick with low impact tools such as Mads’ “BundlerMinifier”, then you are making your life as a developer easier.

Now that’s not to say you shouldn’t considering changing at all, ever. Suppose you need to move files around, then you can easily move from Mads’ “BundlerMinifier” to using Gulp, just right click bundleconfig.json select “Convert to Gulp”

Image 11

You can then make use of some of the many Gulp ‘plugins’ to do the extra tasks you need.

In addition, by starting with Mads’ “BundlerMinifier” and then moving to Gulp, in this way, you continue to build on the bundleconfig.json file and still get to use the right-click to create a minified file, that at least minimizes care and feeding of the config files.

Image 12

Another aspect to consider before moving to Gulp, Grunt (or web pack) is the additional time these might add to your development build cycle. Building and debugging locally may not be affected so much, as you’ll typically be using the original un-minified version locally, but when doing release builds, you may find that your deployment time and CI build times can increase.

In summary, consider your dev cycle/build times, burdens of care-feeding of config files as well as user experience and make sure you’re not yak shaving, or going through too much pain for little overall gain.

Image 13

What about Webpack?

Webpack is a number of things, it's both an alternative way to launch Angular 4 (an alternative to using SystemJs), it also a task runner that can bundle and minify files, or perform other tasks.

It works in a similar way to gulp in that various tasks can be performed by plugins, and just as with Gulp and Grunt, Webpack too has quite a following in the community . One of the benefits is how it can follow the links through your code to figure what scripts, templates and styles are required, and then set up bundles that work along with various entry points into your code. This makes large sites load noticeably faster, since the user is sent just the files needed and not everything at once.

The downside is it is complicated to set up for anything but simple scenarios. It will take you time to figure out how to configure Webpack, but in the end if you a moderately large to very large site, the benefits will be worth it. for smaller sites, you might consider the benefits vs the work to incorporate it. 

As a result of this steep learning curve and dubious benefits for a smaller site, and my time constraints in producing this series, I have decided this is out of scope of this series of articles, however despite being untested in this framework, it should work ok, with some effort. 

Automating SQL Migrations

In earlier parts deployment was done using the development mode switch, turned on (or disabled) to enable the block of code in startup.cs to kick in and perform the migration.

After some various experiments, and I can't say this will be the best for everyone, I have found for me, that automated code based migrations work best. So long as you put safeguards in place, in code, to create seed data (initial data) only where none exists, you can be quite confident in the rest of the pieces of entity Framework migrations to only create your database when needed, when it does not already exist.

To update the project to make migrations simpler and automated, here are the changes required.

At the bottom of startup.cs, either remove or remark out the conditional, as shown below:

            // if you want to use automated deployments, keep the following line remarked out
            // if (CurrentEnvironment.IsDevelopment())
            {
                DbInitializer.Initialize(context);
            }

Next in the package manager console, type:

add-migration InitialMigration 

This will create your code first migration classes. Next update the existing DbInitializer class, in the \Data folder, changing the line from this

C#
            context.Database.EnsureCreated();

to this, instead:

C#
            context.Database.Migrate();

and then adding the additional using statement at the top:

C#
using Microsoft.EntityFrameworkCore;

Now migrations will be carried out, when necessary.

Again, if adding seed data, ensure you have a guard clause, like the one below:

C#
            // Look for any test data.
            if (context.TestData.Any())
            {
                return;   // DB has been seeded
            }

That's migration done. But for more information, please refer to the existing documentation over on the ASP.Net Core website here.

Publishing to an IIS web host using Web Deploy

Part 7 & part 8 of this series covered publishing to a local instance of IIS, or an instance where there is a shared file folder into which you can drop your published files. 

In another common situation, where you have no direct file access to production web servers, with access provided by "ops" or support people, you might need to provide a copy of production code to deploy. In that case, the same files that you published in part 7 & part 8 to a local folder could also be zipped up and provided as your new to-be-published website to your "ops" people, since these files represent the complete site.

Developers in a situation where there is a little more autonomy or trust and can deploy directly into a test or production environment can use a different method of publishing their new site called Web Deploy. This is covered in great depth on the ASP.Net Core documentation website, so I'll only be covering the highlights here.

First create your website in IIS, as we did before. In my case I have publishing to a server sitting on a LAN, and seeing it from inside the network. I'm using port forwarding though I could use a DMZ, to have this same server also be visible externally on a domain name I have registered using the NOIP dynamic DNS service, since this internet feed is not to a static IP address. If you are publishing to a server hosted elsewhere, you will need to ensure the correct ports are opened up (see ASP.Net core docs above for further details). 

 Image 14

You'll need to ensure you have permissions to publish to IIS, see the "IIS Manager Permissions"icon, above. Again this is covered in great detail in the Microsoft docs.

Ensure you have your new website running on an application pool that is set to "NoManaged Code" (again this is detailed more in part 7 & part 8).

Image 15

Back in Visual Studio, right click your project, click Publish, alternately click the Build menu, then click Publish. Select "IIS, FTP, etc."

Image 16

Next you'll be asked to select a publish method, this time we'll use Web Deploy. The remaining boxes can be a little confusing at first, so take note of the watermark hints:

Image 17

The first box marked "Server:" should be given the domain name of the server. So if your server was say http://www.example.com then you would enter www.example.com - in other words, leave off the http:// or https:// part of the address. The site name will be where within the site you are going to publish the files. You need to refer to your instance of IIS for this Earlier in my example above, you'll see I created a virtual directory called "a2spa" in the "Default Web App", so the "Site name:" should in this example contain "Default Web Site/a2spa". The username and password will be your username and password as you set earlier in IIS Manager Permissions. Then finally the destination URL will generally be the same as the "server:" URL, however this time prefixed with http:// or https:// to form the complete URL.

Image 18

You should then click "Validate Connection" to ensure your username and password are correct. If it fails, fix this until you get it passing validation.

Image 19

Follow the prompts, did you remember to install WebDeploy on the server? 

Restarting the services (or ensuring they are running) on IIS can help:

Image 20

Or check using the Services tool that the Web Deployment service is running on the server. 

Image 21

I found I needed to manually edit the publish profile, from the default generated by Visual Studio. If you are stuck, save the profile (even if not working) and then you can work on fixing the issues instead of re-entering all over again.

Rick Strahl's blog here had the answer in my case. Open up properties, then publish profiles, open up the file for editing  

Image 22

In my case I altered the MSDeployServiceURL to make it http:// not https:// and following Rick's advice, changed the node <MSDeployPublishMethod> from WMSVC to RemoteAgent and then change the node <EnableMSDeployBackup>from True to False. Save and then close the file, and try publishing again.

Image 23

In part 7 and part 8 we used a simple publish using the file system and needed to restart our app pool (we could also have restarted our IIS instance) to unblock copying the a2spa.dll file, which would otherwise fail much of the time, because it was in use. Using Web Deploy we can remove the code from our project file that does this task. For brevity if you need further help, please refer to part 7 or part 8.

Image 24

Once published you should see a success message:

Image 25

And then you can then go ahead and view your newly deployed site.

Image 26

Check that the site works, to verify IIS and SQL, and ensure our dependencies were deployed.

Image 27

Publishing to Azure

Next we're going to publish our simple A2SPA website to Azure.

The simplest place to start is in Azure, first create the web application and then SQL instance, then save the publish profile.  

Next Import this saved publish profile into Visual Studio. 

It is possible to start in Visual Studio and fill in the blanks to use an existing Azure site, though this might take more time as you have to chase up a number of different settings, user names and URLs - details which are almost all covered in the publish file.

So (assuming you have Azure portal setup and ready to go), create an empty Web App + SQL on Azure:

Image 28

Just make sure you choose an ASP.Net Core Web App+ SQL project:

Image 29

Give the site a name, I used the rather un-original project name, a2spa:

Image 30

Then a wizard opens out to help you select the location, select the plan (free plan, cheap plan, not so cheap plan etc).

Image 31

After creating the web app, you can then create a database. Again choosing what sort of database (I chose SQL), location and that plan again.

Image 32

After a minute or two minutes or so, of provisioning time, as the site and database is created (be patient), you'll be all set ready to go.

Image 33

As the site is being set up, if you’ve pinned it to the dashboard, you'll get an in progress notification during provisioning: 

Image 34

The finally when all is done, simply download the Visual Studio publish profile

Image 35

Back in Visual Studio use the Publish, Import option, enter your password, and click Publish.

Image 36

If all goes well, you should be able to browse the site, now published and hosted on Azure:

Image 37

But wait, not quite - no SSL. Recall that there's a directive in startup.cs that insists on HTTPS connections when in production. 

Image 38

I could of course set up SSL on Azure, back in the Azure portal. Microsoft have quite good documented on the process of setting up SSL certs, here. Or Nik Molnar's blog entry here detailing how to set up SSL for Azure using a cert from Let's Encrypt.

Image 39

It's simple enough, and there are numerous places you I could buy an SSL certificate and do this. There are even some organizations offering free* SSL certificates. (* free of charge, but arguably not so cheap in terms of the time they may take to actually use). Since this series is not actually generating me income, but is costly to me in time, I've opted out of paying for an SSL cert.

Still if you would like to use a free* SSL certificate try "Let's Encrypt" here.

Image 40

Another "free" way is to "brew you own", or create a self-signed certificate using MakeCert. Shing Chen's blog covers this here.

Image 41

So finally here is the site, albeit sans-SSL, but nonetheless hosted and running on Azure.
I'm sorry to say it won't probably be up and running, as you read this, since I am using free Azure credits and would rather not go over my limits and get hit with a bill. :)

But why not have a go at Azure, set up a free trial dev account and try this too.

Image 42

Where to now?

Hopefully you now have some tools to help you create a SPA and extend it, to use your existing ASP.NetMVCor ASP.Net Core skills, using Razor, .cshtml, and tag helpers to help create your Angular templates dynamically.

There's no reason you could not extend this design to take a view model class and dynamically create a complete form, or shopping cart, from a single tag and tag helper.

Further extensions could be made to look at smarter bundling and minification, with multiple entry points, and if the size of the website warrants it, perhaps even integrating Webpack. 

I think this design should provide you enough to build most intranet applications and also be very useful for small to moderate public internet applications.Being data driven and using tag helpers you get the ability to quickly respond to change and reduce cut-paste code to a minimum.

If considering this for your next site, I'd also consider adding at least some server side unit tests around the tag helpers, and also at least some client side tests around the generated markup and validation.

Other extension points worth looking at are moving from Bootstrap 3 to either Bootstrap 4 or Material Design 2.

Both have Angular 2 / native support, and could allow you to remove jquery and possibly some other files.

You could also look at using SASS/SCSS style sheet generation, using some more of Mads' tools as these really make good clean small CSS without a lot of pain, giving you quite good control over styling. And again these can be part of the back end tools that "just work" without effort, such as Mads' BundlerMinifier.

Lastly there's server side pre-rendering and javascript-less alternatives out there already using ASP.Net Core. Steve Sanderson and others have put together some clever templates, both for Visual Studio or Yeoman, that have dynamic builds. These could probably be achieved with this design too, with some effort.

If there is any interest in extending this into an open source framework, adding some tooling and templates, please let me know in the comments or by email. 

I hope you find this a great platform and way forward. ASP.Net Core and Angular have a great future together.

History

This is part 9, the final part in the series, the previous parts were:

Part 1 - How to integrate ASP.Net Core and Angular 2
Part 2 - How to use Tag Helpers to display data
Part 3 - How to use Tag Helpers for data input, added SQL backend using EF Core.
Part 4 - Adding token authentication with JWT using OpenIdDict. 
Part 5 - Adding async services, server-side validation, a simple Angular 2 datagrid & more tag helpers.
Part 6 - Using NSwag to create Swagger docs and generate Angular 2 / Typescript data models + data services.
Part 7 - publishing to IIS for VS2015 users.
Part 8 - publishing to IIS for VS 2017 users.

This is the final part, part 9 covering bundling, minification, code first migration, publishing to external IIS hosts, and publishing to Azure.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)