Website development and design blog, tutorials and inspiration

.Net Core and Why it's the Future

By Tim Trott, 7th March 2016 in C#

Microsoft's latest focus is on .NET Core as the future of its development platform. In this article we look at what .Net Core is and how it differs from Microsoft's .NET Framework.

Announced back in 2014, .Net Core is an open source project built as a modular development stack and is the foundation of all future .NET platforms. It's already used by ASP.NET 5 and .NET Native.

.Net Core is an open source framework built from the ground up to be a cross platform language. Being open source allows Microsoft leverage the resources of the open source community to contribute, distribute, and create add-ons and extensions. Microsoft also wanted the platform to be able to compile native machine code, something that the .Net Framework cannot do. With introduction of .Net Core, ASP.Net 5 has been renamed ASP.Net Core 1.0

Getting Started with .Net Core

The best way to install .NET Core on Windows is to download the official MSI installer. This installer will install the tools and put them on your PATH. If you are using Windows 7, Windows Server 2008 or Windows Server 2012 you will also need to install Visual C++ Redistributable for Visual Studio 2012 Update 4 & Visual C++ Redistributable for Visual Studio 2015.

You should also have Visual Studio 2015, the community edition will do.

What's Different?

ASP.Net Core is quite a bit different to previous versions of ASP.Net MVC, but isn't so unfamiliar as to be completely foreign. Startup.cs is now the main entry point for applications, and dependency injection is part of the native code, so no third party libraries are required for this. Also, Web Forms have been depreciated in favour of MVC 6. There are NuGet packages to add Web Forms, but MVC is the future and support for forms will eventually be removed entirely.

The best way to see the changes is to get stuck in with a new project. As we come across the new features, I'll go through them with you. So let's get started with File > New Project. If ASP.Net has been installed correctly you should see it listed in the project templates dialogue box.

Once the new project has been created, the first thing you will notice is how different the project structure is. It's almost alien. Let's have a look at the new structure from the top down.

The first thing you'll notice is in the Solution Items folder, a file called Global.json. This file kind of replaces the project.sln file in that the compiler does not use the .sln at all, just the .json file. The solution file still exists, but it is only used by Visual Studio.

The project file, .proj, is no longer used. Instead there is a .xproj containing the export definitions as well as a project.json. Like the global.json, project.json is used to hold all the settings for the project. The .xprj is only used by Visual Studio

If you right click on the solution and click browse to folder, Windows explorer will open at the project location. You should note that the file structure matches the structure in solution explorer. Because the project files are structured on disc, the project settings file no longer maintains a list of file included in the project, fantastic news for users of source control systems! It also means that you can add files to the project by simply dragging them to the folder in Explorer, without needing to right click "Add to Project" each time.

ASP.NET 5 Core
ASP.NET 5 Core

When looking in the solution browser you will also notice a wwwroot folder. This is the root of the web application, and only files within this folder will be served by IIS. Anything outside this folder is protected, so sensitive files such as configurations and classes are blocked from being accessed via the web.

The next special folder is called Dependencies. This is folder for storing all the packages added to the project. More on this in a minute.

NuGet and Bower

NuGet is now the standard method for adding server and client side packages to the project. For client side packages, Bower is available to manage installations and updates of packages and libraries. NPM is also still available.

To install a client side package, right click on the project and select Manage Bower Packages. This will open a new window where you can click on install and browse for a package. When you install a package you will see that they have been included into the dependencies folder, but not the wwwroot. If you were paying attention, you will remember that only files in the wwwroot folder are available on the website, so how is the new package going to be accessed? This is done through the Bundling and Minification process, now part of the build procedure.

Bundling and Minification

If you've used bundles in previous versions, you should note that registering bundles is now no longer available. Instead, use task runners Gulp and Grunt. Tasks are written in JavaScript, and control how packages are bundled together and minified.

Add a new item to the project and search for NPM. Add NPM Configuration File (package.json) This then adds the file to the project root. Open package.json for editing and you will see a simple JSON object with an empty devDependancies section. In here, list out the packages and versions used in the order that they will be added. In this example I'm adding Gulp to minify the files.

  1. {
  2. "version":"1.0.0",
  3. "name":"ASP.NET",
  4. "private":true,
  5. "devDependancies": {
  6. "gulp":"3.9.0"
  7. "gulp-concat":"2.5.2",
  8. "gulp-cssmin":"0.1.7",
  9. "gulp-uglify":"1.2.0"
  10. }
  11. }

When you save the file, Visual Studio will download and install the packages. Within the dependencies folder it will create a new folder called NPM where the packages will be downloaded to.

Now that Gulp is installed, let's add the configuration file and setup how it minifies out project. Add a new item again, and this time search Gulp and add Gulp Configuration File. This will create a new gulpfile.js. Within this file you can add in the requires statements, paths, source paths and tasks. Creating Gulp configuration is better explained on the Gulp website. A basic configuration is shown below.

  1. /// <binding />
  2. /*
  3. This file in the main entry point for defining Gulp tasks and using Gulp plugins.
  4. Click here to learn more. http://go.microsoft.com/fwlink/?LinkId=518007
  5. */
  6.  
  7. var gulp = require('gulp'),
  8. concat = require('gulp-concat'),
  9. cssmin = require('gulp-cssmin'),
  10. uglify = require('gulp-uglify');
  11.  
  12. var paths = {
  13. webroot: "./wwwroot/"
  14. };
  15.  
  16. paths.bootstrapCss = "./bower_components/bootstrap/dist/css/bootstrap.css";
  17. paths.jqueryJs = "./bower_components/jquery/dist/jquery.js";
  18. paths.fonts = "./bower_components/font-awesome/fonts/*";
  19.  
  20. paths.jsDest = paths.webroot + "js";
  21. paths.cssDest = paths.webroot + "css";
  22. paths.fontDest = paths.webroot + "fonts";
  23.  
  24. gulp.task("min:js", function () {
  25. return gulp.src([paths.jqueryJs])
  26. .pipe(concat(paths.jsDest + "/min/site.min.js"))
  27. .pipe(uglify())
  28. .pipe(gulp.dest("."));
  29. });
  30.  
  31. gulp.task("copy:js", function () {
  32. return gulp.src([paths.jqueryJs])
  33. .pipe(gulp.dest(paths.jsDest));
  34. });
  35.  
  36. gulp.task("min:css", function () {
  37. return gulp.src([paths.bootstrapCss])
  38. .pipe(concat(paths.cssDest + "/min/site.min.css"))
  39. .pipe(cssmin())
  40. .pipe(gulp.dest("."));
  41. });
  42.  
  43. gulp.task("copy:css", function () {
  44. return gulp.src([paths.bootstrapCss])
  45. .pipe(gulp.dest(paths.cssDest));
  46. });
  47.  
  48. gulp.task("copy:fonts", function () {
  49. return gulp.src([paths.fonts])
  50. .pipe(gulp.dest(paths.fontDest));
  51. });
  52.  
  53. gulp.task("min", ["min:js", "min:css"]);
  54. gulp.task("copy", ["copy:js", "copy:css", "copy:fonts"]);

This Gulp config is pretty standard. Firstly we set a bunch of paths for the source files, then some paths for the destination folders. We then create a bunch of tasks, with chained commands to combine multiple files into one (concat), then minify the file (uglify and cssmin) before writing the processed file out to the destination folder. There are also two tasks which copy the unminified files to the destination as well. This is useful for debugging and testing as minified files can be difficult to read.

When you have finished setting up Gulp, open up the Task Runner Explorer from View > Other Windows > Task Runner Explorer. It will automatically detect the entries from the config file and allow you to run your tasks. After this the files will be processed and placed within the wwwroot folder. By right clicking on a task, you can bind it to a build event, so each time you build your Visual Studio project it can automatically run the Gulp tasks selected.

String Interpolation

New in C# v6 is string interpolation. This is simply another method for joining strings together using String.Format in shorthand.

Previously a string concatenation may have looked like this:

  1. string mystring = string.Format("Hello {0}, today is {1}", model.FirstName, DateTime.Now.DayOfWeek);

Using interpolated strings which are prefixed with a $ and where the parameters encased in curly braces the string now becomes:

  1. string mystring = $"Hello {model.FirstName}, today is {DateTime.Now.DayOfWeek}";

This is much easier to read and write as it follows a more natural structure. If you have many parameters then it makes matching up indexes with parameter values far easier.

Startup Class

The global.asax has been replaced by the start-up class located in the root of the solution. The start-up class (startup.cs) contains a main method. This is the entry point to the application. Nothing new here, all .Net applications use a main method as an entry point; however this was hidden away in previous ASP.Net applications in the System.Web assembly, with certain methods exposed as events in global.asax. In .Net Core, you are in the driving seat and have total control about how the application is launched from within the start-up class.

The start-up class is a simple class, not derived from any other classes, nor does it implement any interfaces. The runtime will use this class and call two methods, ConfigureServices and Configure.

Dependency Injection

The purpose of the ConfigureServices method in the start-up class is to configure dependency injection. In previous versions of ASP.Net, dependency injection was optional and controlled by the use of third party plugins such as SimpleInjector. In ASP.Net Core, it is an integral part.

When an application starts up, types are registered within an IoC (Inversion of Control) container. These types are called services. Once registered, other types can ask the container for instances of that type. The container also controls the lifetime of objects. When registering a type, you can choose transient, scoped or singleton lifetimes. A transient type is created fresh each time it is requested, a scoped type exists for the duration of the web request, and a singleton type will exist throughout many requests until the application is closed.

To add a type to the container, in the ConfigureServices method simply make a call to services.AddSingleton, AddScoped or AddTransient methods, passing in the interface and classes to the type.

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. // Add all dependencies needed by Mvc.
  4. services.AddMvc();
  5.  
  6. services.AddSingleton<ITypeRequested, ClassReturned>();
  7. }

How A Request is Processed

Another method in the start-ups class is Configure. The runtime calls this method to configure the HTTP request pipeline. The pipeline configures how the application should respond to HTTP requests. When an internet browser makes a request to the application, the request is passed along the pipeline where various actions take place. Eventually a response is generated and returned to the browser. If there is nothing in the pipeline, nothing happens. Each action that is invoked during the pipeline is called Middleware. Examples of which are the MVC Framework, Authentication, Static Files and so on. Most of these are handled automatically for you. In previous versions, this was all handled by System.Web, however this is tied specifically to IIS web server and violates cross platform viability.

Environments

Environments allow configuration of the different environments that the app can run in. These are typically Development, Staging and Production. Each environment can have its own settings for database connections, file paths and even web server configuration. Environments are configured in the project Properties folder in a file called launchSettings.json.

In the start-up class you can expose the hosting environment which you can use in your app to perform actions only based on the hosting environment. Simply add a constructor to the startup class accepting a IHostingEnvironment object and have it set a property on the class.

  1. private IHostingEnvironment _hostingEnvironment;
  2.  
  3. public Startup(IHostingEnvironment hostingEnviromnent)
  4. {
  5. HostingEnvironment = hostingEnviromnent;
  6. }

Now you can addess this from within the Configuration method

  1. if (_hostingEnvironment.IsDevelopment())
  2. {
  3. App.UseDeveloperExceptionPage();
  4. }

This will allow application error exceptions to only show when the environment is development.

Configuration Settings

In previous versions of ASP.Net, configuration was handled by the web.config and XML files. This file has now been removed, and is instead replaced by Environments and In .Net Core, there is a new configuration settings framework which out the box supports In Memory, JSON, XML, INI (yes - INI is making a comeback!) and environment variables. You can extend the available sources by deriving from the ConfigurationSource class, which is optimised for dependency injection.

To create a simple JSON based configuration setting, create a new JSON configuration file in the root, settings.json for example.

  1.  
  2. {
  3. "TestSetting":"This is a test setting"
  4. }

Next create a folder called options, and a new class called settingsOptions.cs. Create properties within this class matching those in the JSON file.

  1. public class settingsOptions
  2. {
  3. Public string TestSetting { get; set; }
  4. }

Now in the startup class, ConfigureSources create an instance of the ConfigurationBuilder, and add the json file to the key value pairs.

  1. var configBuilder = new ConfigurationBuilder()
  2. .AddJsonFile("settings.json");

It is also handy to override the settings based on the environment. This can be done using an environment settings file. This is done by simply chaining another AddJsonFile to the new ConfigurationBuilder.

  1. var configBuilder = new ConfigurationBuilder()
  2. .AddJsonFile("settings.json");
  3. .AddJsonFile($"settings{hostingEnvironment.EnvironmentName}.json", optional: true);

This looks for a file containing the current environment name, and it is optional, meaning if the file is not found it won't show any errors. The hostingEnvironment is the same one we used earlier. The configuration builder overrides the settings in the first file with those in the second, if it is found.

When all the files are added, you can issue the command to build.

  1. var config = configurationBuilder.Build();

Then add it to the pipeline

  1. services.Configure<SettingsOptions>(config);

This will provide a SettingsOptions instance populated with the values from the JSON files to your applications.

Settings can be read using an injected IOptions class when creating the class.

  1. private SettingsOptions _options;
  2. public TestController
  3. {
  4. public TestController(IOptions<SettingsOptions> options)
  5. {
  6. _options = options
  7. }
  8.  
  9. public string myMethod()
  10. {
  11. return _options.TestSetting;
  12. }
  13. }

View Components

View Components are like partial views, except they have their own mini controller. They live in a folder called ViewComponents and inherit from a class called, surprisingly, ViewComponents.

  1. public class SampleViewComponent: ViewComponent
  2. {
  3. IViewComponentResult Invoke()
  4. {
  5. return "This is a test";
  6. }
  7. }

MVC expects the view to be in a folder within the Components folder, usually contained in the Shared folder since they are intended to be reused. When naming the view folder, take the controller name, minus ViewComponent. In this example the folder is Views/Shared/Components/Sample. Create a view called Default.cshtml.

The view should be a strongly typed to match the controller model.

View Components can be included on pages using the following syntax:

  1. @Component.Invoke("Sample")

Fin.

And that's an introduction to the new Microsoft .Net Core 1.0. Over time I'll be adding more tutorials to this series to cover aspects in more depth. For now, download .Net Core, install Visual Studio and start playing with it!

Further Reading
What's New in MVC6 and Why MVC6 is the Best Yet
What's New in MVC6 and Why MVC6 is the Best Yet

( ! ) Warning: Illegal string offset 'siteId' in /myraid/files/websites/www/sandbox/plugins/websites/class.pages.php on line 164
Call Stack
#TimeMemoryFunctionLocation
10.0001230552{main}( )../generatepage.php:0
20.8618521904ExportPages( )../generatepage.php:21
3131.4549899888IncludeTemplateFile( )../generatepage.php:239
4131.4549900448include( '/myraid/files/websites/www/sandbox/plugins/websites/themes/azuliadesigns/pageTemplates/single.php' )../functions.php:183
5131.4550900816include( '/myraid/files/websites/www/sandbox/plugins/websites/themes/default/pageTemplates/single.php' )../single.php:1
6131.75651048648GetPageNoSite( )../single.php:81
7131.76191069336ParsePageProperties( )../class.pages.php:188
8131.76661101088apply_filters( )../class.pages.php:243
9131.76661101136call_user_func ( )../class.filters.php:440
10131.76661101168filter_html( )../class.filters.php:440
11131.81191119432shortcodes( )../class.filters.php:23
12131.81491134256preg_replace_callback ( )../class.filters.php:475
13131.81511163312do_shortcode_tag( )../class.filters.php:475
14131.81511163928call_user_func ( )../class.filters.php:602
15131.81511163968thumb_shortcode( )../class.filters.php:602
16131.81511164640shortcodes( )../class.filters.php:223
17131.81531166928preg_replace_callback ( )../class.filters.php:475
18131.81531168680do_shortcode_tag( )../class.filters.php:475
19131.81531169120call_user_func ( )../class.filters.php:602
20131.81531169160relatedAside_shortcode( )../class.filters.php:602
21131.81531169616GetPage( )../class.filters.php:395
Visual Studio Code - Can it beat Notepad++?
Visual Studio Code - Can it beat Notepad++?
Introduction to Microsoft MVC.Net
Introduction to Microsoft MVC.Net
What is ASP.Net?
What is ASP.Net?
Comments
  1. Jiping
    Jiping

    Great introduction, thanks for you work.

Leave a Reply

Your email address will not be published.