TypeScript for C# and .NET Core Developers Review

I finished reading Hands-On TypeScript for C# and .NET Core Developers by Francesco Abbruzzese (@f_abbruzzese) for Packt Publishing. As the name states, it is about TypeScript (and JavaScript) and also very much about Angular.

The book is structured like this:

  1. First chapter explains what is TypeScript (version 2.8.3), how to install it using NPM or the SDK, how to create your first project, basic configuration options, the type system and syntax; at all times, it relates the TypeScript syntax with the recent ECMAScript versions, of which TypeScript is a superset
  2. The second one talks about type declaration, including interfaces, classes, unions, tuples, arrays and so on. It also covers operations over types, such as destructuring and spreads. Finally, it presents functions in TypeScript, how to mimic overloading and have optional arguments
  3. Chapter 3 covers DOM manipulation. This is probably something that seasoned web/JavaScript developers are quite familiar with, but, most importantly, it also introduces declaration files
  4. In chapter 4 we learn how to make effective use of classes and interfaces, declare visibility levels and modifiers, and how type compatibility works
  5. Generics is the topic of chapter 5, how to declare generic types and functions and how to enforce constraints
  6. This chapter talks about modules and namespaces, the different ways by which we can resolve and load modules, and also about TypeScript type declarations, which are used to call untyped JavaScript code
  7. Here we learn how to integrate the WebPack bundler and minifier with ASP.NET Core and how we can enable debugging of the source code in Visual Studio
  8. A very important chapter, here we get an overview on how to write reusable libraries and make them available on NPM. Testing goes together with reusability, so we learn how to use Jasmine to unit test our code
  9. In this chapter we learn about symbols, the TypeScript equivalent to decorators in Aspect-Oriented Programming, generator functions and iterators and also promises, used for asynchronous invocations. Not exactly related, but it also covers the fetch API, used for modern AJAX-style interactions
  10. Chapter 10 presents the ASP.NET Core project template for Angular using TypeScript, describes the Angular architecture and key concepts
  11. This chapter teaches us how to interact with form fields, including validations, how the Angular lifecycle works and how to achieve two-way communication, data binding and piping between components
  12. This one presents some advanced Angular features, such as custom attribute and structural directives, which are then used to create animations by doing DOM manipulation
  13. Lastly, this chapter explains what is dependency injection and its benefits and how we can leverage it with TypeScript and Angular. It also describes how we can localize messages and use HTTP-related modules for interaction with external services. Most importantly, it presents the basis of Angular routing and navigation, a must-have for any complex application, and ends with an overview of testing for

At the end of each chapter there is a summary which highlights the key aspects that were introduced in it, poses 10 questions, which are answered in the Assessments chapter.

The book covers TypeScript 2.8.3, which is relatively old by now, but given the pace that TypeScript versions come out, it can hardly surprise us. Some new stuff in TS is missing, of course, but I guess this will always happen. It is essentially a book about TypeScript and Angular, but of course also covers Node.js and, obviously, JavaScript itself. .NET Core here is discussed as leverage to deploy and compile client-side code. The book is quite comprehensive and was actually an interesting read and I definitely learnt a lot.

The source code can be found in GitHub here: https://github.com/PacktPublishing/Hands-On-TypeScript-for-CSharp-and-.NET-Core-Developers.

If you got interested, please go get if from the Packt Publishing site: https://www.packtpub.com/application-development/hands-typescript-c-and-net-core-developers.

Dynamically Loading Middleware in ASP.NET Core

Introduction

The concept of middleware has been around since ASP.NET MVC (pre-Core) and OWIN. Essentially, a middleware component lives in a pipeline and handles requests and acts as a chain of responsibility, delegating to any subsequent middleware components registered in the pipeline after itself. The following image (taken from the Microsoft site) shows this.

Image result for asp.net core middleware

MVC itself is implemented as a middleware component, as is redirection, exception handling, buffering, etc.

A middleware component can be added in several ways, but in ASP.NET Core, it all goes down to the Use method in IApplicationBuilder. Lots of API-specific methods rely on it to add their own middleware.

For the time being, we’ll make use of the IMiddleware interface that comes with ASP.NET Core. It provides a simple contract that has no dependencies other than the common HTTP abstractions.

One common request is the ability to load and inject middleware components dynamically into the pipeline. Let’s see how we can

Managed Extensibility Framework

.NET Core has Managed Extensibility Framework (MEF), and I previously blogged about it. MEF offers an API that can be used to find and instantiate plugins from assemblies, which makes it an interesting candidate for the discovery and instantiation of such middleware components.

Image result for managed extensibility frameworkWe’ll use the System.Composition NuGet package. As in my previous post, we’ll iterate through all the assemblies in a given path (normally, the ASP.NET Core’s bin folder) and try to find all implementations of our target interface. After that we’ll register them all to the MEF configuration.

Implementation

Our target interface will be called IPlugin and it actually inherits from IMiddleware. If we so wish, we can add more members to it, for now, it really doesn’t matter:

public interface IPlugin : IMiddleware
{
}

The IMiddleware offers an InvokeAsync method that can be called asynchronously and takes the current context and a pointer to the next delegate (or middleware component).

I wrote the following extension method for IApplicationBuilder:

public static class ApplicationBuilderExtensions

{

public static IApplicationBuilder UsePlugins(this IApplicationBuilder app, string path = null)        {

     var conventions = new ConventionBuilder();

        conventions

           .ForTypesDerivedFrom<IPlugin>()

           .Export<IPlugin>()

           .Shared();

           path = path ?? AppContext.BaseDirectory;

            var configuration = new ContainerConfiguration()

            .WithAssembliesInPath(path, conventions);

            using (var container = configuration.CreateContainer())

            {

           var plugins = container

                .GetExports<IPlugin>()

                    .OrderBy(p => p.GetType().GetCustomAttributes<ExportMetadataAttribute>(true)

.SingleOrDefault(x => x.Name == “Order”)?.Value as IComparable ?? int.MaxValue); 

               foreach (var plugin in plugins)

                {

                    app.Use(async (ctx, next) =>

                    {

                    await plugin.InvokeAsync(ctx, null);

                        await next();

                    });

                }

          }

          return app;

    }

}

We define a convention that for each type found that implements IPlugin we register it as shared, meaning, as a singleton.

As you can see, if the path parameter is not supplied, it will default to AppContext.BaseDirectory.

We can add to the plugin/middleware implementation an ExportMetadataAttribute with an Order value to specify the order by which our plugins will be loaded, more on this in a moment.

The WithAssembliesInPath extension method comes from my previous post but I’ll add it here for your convenience:

public static class ContainerConfigurationExtensions
{     public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, SearchOption searchOption = SearchOption.TopDirectoryOnly)     {      return WithAssembliesInPath(configuration, path, null, searchOption);     }     public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, AttributedModelProvider conventions, SearchOption searchOption = SearchOption.TopDirectoryOnly)     {         var assemblyFiles = Directory          .GetFiles(path, "*.dll", searchOption);         var assemblies = assemblyFiles             .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath);         configuration = configuration.WithAssemblies(assemblies, conventions);         return configuration;     }
}

If you want to search all assemblies in nested directories, you need to pass SearchOption.AllDirectories as the searchOption parameter, but this, of course, will have a performance penalty if you have a deep directory structure.

Putting it All Together

So, let’s write a few classes that implement the IPlugin interface and therefore are suitable to be used as middleware components:

[Export(typeof(IPlugin))] [ExportMetadata(“Order”, 1)] public class MyPlugin1 : IPlugin {     public async Task InvokeAsync(HttpContext context, RequestDelegate next)     {         //do something here

//this is needed because this can be the last middleware in the pipeline (next = null)         if (next != null)         {             await next(context);         }

//do something here     } }

Notice how we applied an ExportMetadataAttribute to the class with an Order value; this is not needed and if not supplied, it will default to the highest integer (int.MaxValue), which means it will load after all other plugins. These classes need to be public and have a public parameterless constructor. You can retrieve any registered services from the HttpContext’s RequestServices property.

Now, all we need to do is add a couple of assemblies to the web application’s bin path (or some other path that is passed to UsePlugins) and call this extension method inside Configure:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

{

//rest goes here

app.UsePlugins(/*path: “some path”*/);

//rest goes here

}

And here you have it: ASP.NET Core will find middleware from any assemblies that it can find on the given path.

Hope you find this useful! Winking smile

Succinctly Books Index

This page lists all the books I wrote or reviewed for Syncfusion’s Succinctly series.

Books I wrote:

Books I reviewed:

ASP.NET Core Pitfalls – Session Storage

Previous versions of ASP.NET featured several ways to persist sessions:

  • InProc: sessions would be stored on the server’s process memory
  • SQL Server: sessions would be serialized and stored in a SQL Server database; other vendors offered similar functionality
  • State Server: sessions would be serialized and stored on an instance of the ASP.NET State Service
  • Custom: we had to implement our own persistence mechanism

InProc was probably the most commonly used; it was the fastest, as the items in the session weren’t serialized, but on the other side they would not survive server crashes. Using this approach things usually worked well, because the session object merely provided a reference to the items stored in memory, so manipulating these items didn’t mandate that the session be explicitly saved.

In ASP.NET Core, all of this is gone. By default, sessions are still stored in memory but one can also use one of the available distributed cache mechanisms. The main difference, however, is that even when the session objects are stored in memory, they still need to be serialized and deserialized prior to persisting or retrieving them. It is no longer possible to just store a pointer to a memory object and keep manipulating it transparently; the object to be stored needs to be converted into a byte array first. You can use any serializer you want.

If we think about it seriously, it was probably a good decision: I’ve seen applications where a lot of data was being stored on the session using InProc mode, but then there was a need to switch to another mode to improve scalability, and the application would just stop working, as the objects being stored weren’t serializable. This time, we need to carefully think about it beforehand.

ASP.NET Core Pitfalls – Redirect to Action Keeps Route Parameters

When you redirect after a POST – following the famous Post-Redirect-Get pattern – but your previous view was constructed using a route parameter, then it will be sent to the redirect action as well.

For example, say you are responding to a request for /Filter/Smartphone, where Smartphone is a route parameter, you POST it to some controller action and at the end you redirect to the Index action using the RedirectToAction method:

return this.RedirectToAction(nameof(Index));

The browser will issue the GET request for Index but keeps the Smartphone route parameter, which is not good.

The solution is to pass a routeValues parameter to RedirectToAction that doesn’t contain any of the possible route parameters. One way to do it would be to create a dictionay with all action parameters nullified:

return this.RedirectToAction(nameof(Index), MethodBase.GetCurrentMethod().GetParameters().ToDictionary(x => x.Name, x => (object) null));

The solution to have this done automatically lies in the MethodBase.GetCurrentMethod() method. This way, you are sure to avoid any unwanted route parameters on your next request.

In case you are wondering, passing null, a dictionary without entries or object won’t work, the only other way is to pass an anonymous value with the parameters explicitly set to null.

Mastering ASP.NET Core 2.0

Mastering ASP.NET Core 2.0 Book Cover

My new book is out! It is called Mastering ASP.NET Core 2.0 and was edited by Packt Publishing, as my previous one, Entity Framework Core Cookbook – Second Edition.

It was big challenge – the book has over 480 pages – and it spanned multiple .NET Core versions – 1.1 and 2.0. I tried to cover the most important things, even with some detail. The chapters are:

  1. Getting Started with ASP.NET Core: .NET Core, ASP.NET Core, platforms, DI & IoC, MVC pattern, OWIN, hosting, environments
  2. Configuration: providers
  3. Routing: templates, handlers, constraints, areas, error handling
  4. Controllers and Actions: controller lifecycle, API controllers, versioning, documentation, globalization, binding
  5. Views: areas, layouts, Razor pages, globalization
  6. Using Forms and Models: metadata, templates, binding, validation
  7. Security: authentication, authorization, anti-forgery, CORS, HTTPS
  8. Reusable Components: partial views, view components, tag helpers and tag helper components
  9. Filters: authorization, resource, action, result, exception, Razor page
  10. Logging, Tracing and Diagnostics: custom middleware, logging, DiagnosticSource, ELM, AppInsights, HealthCheck
  11. Testing: xUnit, integration tests, UI tests with Selenium
  12. Client-Side Development: Bower, Node.js/NPM, Gulp, Grunt, TypeScript, LESS
  13. Improving the Performance and Scalability: asynchronous methods, profiling, bundling and minification, caching, response compression
  14. Real-Time Communication: SignalR
  15. Other Topics: areas, static files, application lifetime events, conventions, embedded resources, hosting extensions, URL rewriting
  16. Deployment: Visual Studio, IIS, Azure, AWS, Nginx, Apache, Docker, Windows Service

Whenever there are important differences, I mention the differences between ASP.NET Core 1.x and 2.x, although I think this will be less important over time.

Overall, it was an exciting task, but not one without obstacles. I must thank the team at Packt Publishing, namely, Siddhi Chavan and Abhishek Sharma for all their patience and support.

Do have a look and share your feedback! It is available from the Packt Publishing site, Amazon and others, either in hardcopy or ebook format. The source code is available at https://github.com/PacktPublishing/Mastering-ASP.NET-Core-2.0.

SignalR in ASP.NET Core

Introduction

SignalR is a Microsoft .NET library for implementing real-time web sites. It uses a number of techniques to achieve bi-directional communication between server and client; servers can push messages to connected clients anytime.

It was available in pre-Core ASP.NET and now a pre-release version was made available for ASP.NET Core. I already talked a few times about SignalR.

Installation

You will need to install the Microsoft.AspNetCore.SignalR.Client and Microsoft.AspNetCore.SignalR Nuget pre-release packages. Also, you will need NPM (Node Package Manager). After you install NPM, you need to get the @aspnet/signalr-client package, after which, you need to get the signalr-client-1.0.0-alpha1-final.js file (the version may be different) from the node_modules\@aspnet\signalr-client\dist\browser folder and place it somewhere underneath the wwwroot folder, so that you can reference it from your pages.

Next, we need to register the required services in ConfigureServices:, before Use

services.AddSignalR();

We will be implementing a simple chat client, so, we will register a chat hub, in the Configure method:

app.UseSignalR(routes =>
{
routes.MapHub<ChatHub>("chat");
});

A note: UseSignalR must be called before UseMvc!

You can do this for any number of hubs. as long as you have different endpoints. More on this in a moment.

In your view or layout file, add a reference to the signalr-client-1.0.0-alpha1-final.js file:

<script src="libs/signalr-client/signalr-client-1.0.0-alpha1-final.js"></script>

Implementing a Hub

A hub is a class that inherits from (you guessed it) Hub. In it you add methods that may be called by JavaScript. Since we will be implementing a chat hub, we will have this:

public class ChatHub : Hub
{
public async Task Send(string message)
{
await this.Clients.All.InvokeAsync("Send", message);
}
}

As you can see, we have a single method, Send, which, for this example, takes a single parameter, message. You do not need to pass the same parameters on the broadcast call (InvokeAsync), you can send whatever you want.

Going back to the client side, add this code after the reference to the SignalR JavaScript file:

    <script>
     
        var transportType = signalR.TransportType.WebSockets;
        //can also be ServerSentEvents or LongPolling
        var logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
        var chatHub = new signalR.HttpConnection(`http://${document.location.host}/chat`, { transport: transportType, logger: logger });
        var chatConnection = new signalR.HubConnection(chatHub, logger);
     
        chatConnection.onClosed = e => {
            console.log('connection closed');
       };
    
       chatConnection.on('Send', (message) => {
           console.log('received message');
       });
    
       chatConnection.start().catch(err => {
           console.log('connection error');
       });
    
       function send(message) {
           chatConnection.invoke('Send', message);
       }
    
</script>

Notice this:

  1. A connection is created pointing to the current URL plus the chat suffix, which is the same that was registered in the MapHub call
  2. It is initialized with a specific transport, in this case, WebSockets, but this is not required, that is, you can let SignalR figure out for itself what works; for some operating systems, such as Windows 7, you may not be able to use WebSockets, so you have to pick either LongPolling or ServerSentEvents
  3. The connection needs to be initialized by calling start
  4. There is an handler for the Send method which takes the same single parameter (message) as the ChatHub’s Send method

So, whenever someone accesses this page and calls the JavaScript send function, it invokes the Send method on the ChatHub class. This class basically broadcasts this message to all connected clients (Clients.All). It is also possible to send messages to a specific group (we’ll see how to get there):

await this.Clients.Group("groupName").InvokeAsync("Send", message);
or to a specific client:
await this.Clients.Client("id").InvokeAsync("Send", message);
You can add a user, identified by a connection id and and a ClaimsPrincipal, if using authentication, as this:
public override Task OnConnectedAsync()
{
this.Groups.AddAsync(this.Context.ConnectionId, "groupName");

return base.OnConnectedAsync();
}
Yes, the OnConnectedAsync is called whenever a new user connects, and there is a similar method, OnDisconnectedAsync, for when someone disconnects:
public override Task OnDisconnectedAsync(Exception exception)
{
return base.OnDisconnectedAsync(exception);
}
The exception parameter is only non-null if there was some exception while disconnecting.
The Context property offers two properties, ConnectionId and User. User is only set if the current user is authenticated, but ConnectionId is always set, and does not change, for the same user.

Another example, imagine you wanted to send timer ticks into all connected clients, through a timer hub. You could do this in the Configure method:

TimerCallback callback = (x) => {
var hub = serviceProvider.GetService<IHubContext<TimerHub>>();
hub.Clients.All.InvokeAsync("Notify", DateTime.Now);
};

var timer = new Timer(callback);
timer.Change(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(10));
Here we are starting a Timer and, from there, we are getting a reference to the timer hub and calling its Notify method with the current timestamp. The TimerHub class is just this:
public class TimerHub : Hub
{
}
Notice that this class has no public method, because it is not meant to be callable by JavaScript, it merely is used to broadcast messages from the outside (the Timer callback).

Sending Messages Into a Hub

Finally, it is also possible to send messages from the outside into a hub. When using a controller, you need to inject into it an instance of IHubContext<ChatHub>, from which you can send messages into the hub, which will then be broadcast to where appropriate:
private readonly IHubContext<ChatHub> _context;

[HttpGet("Send/{message}")]
public IActionResult Send(string message)
{
//for everyone
this._context.Clients.All.InvokeAsync("Send", message);
//for a single group
this._context.Clients.Group("groupName").InvokeAsync("Send", message);
//for a single client
this._context.Clients.Client("id").InvokeAsync("Send", message);

return this.Ok();
}

Note that this is not the same as accessing the ChatHub class, you cannot easily do that, but, rather, the chat hub’s connections.

Conclusion

SignalR has not been released yet, and it may still undergo some changes. For now, things appear to be working. On a future post I will talk more about SignalR, including its extensibility mechanisms and some more advanced scenarios. Stay tuned!

Moving to ASP.NET MVC Core 1

Introduction

The new version of ASP.NET MVC, Core 1, brought a number of changes. Some were additions, but others were removals.The structure is similar and will be mostly familiar to anyone who has worked with ASP.NET MVC, but a few stuff is very different. Let’s visit all of them, in a lightweight way – more posts coming soon.

Unified API

MVC and Web API have been merged together, which is a good thing. The new API is based on OWIN. There is a single Controller base class and an IActionResult serves as the base class for the responses, if we so want it – we can also return POCO objects.

Application Events

Application_Start and Application_End events are now gone, as is IRegisteredObject interface and HostingEnvironment.RegisterObject. If you want to be notified (and possibly cancel) hosting event, get a handle to the IApplicationLifetime instance using the built-in service provider and hook to the ApplicationStarted, ApplicationStopping or ApplicationStopped properties.

Dependency Injection

The dependency resolution APIs of both MVC and Web API has been dropped in favor of the new .NET Core mechanism, which is usually configured in the Startup class. You can plug your own IoC/DI framework as well. I wrote a post on this, which you can find here. There are now several new services that you can use to query information from the executing context, experienced users will perhaps find it complex. I’d say this is matter for a full post soon.

Routing

Attribute routing comes out of the box, no need to explicitly configure it. There is no global routing table (RouteTable.Routes), so we need to configure it in the Startup class, in the UseMvc method:

app.UseMvc(routes =>

{

    routes.MapRoute(

        name: "default",

        template: "{controller=Home}/{action=Index}/{id?}");

});

Route handlers (IRouteHandler) are not directly usable. Remember, route handlers are called when the route is matched. Instead, we need to use an IRoute:

public class MyRouter: IRouter

{

    private readonly IRouteHandler _handler;

 

    public MyRouter(IRouteHandler handler)

    {

        this._handler = handler;

    }

 

    public VirtualPathData GetVirtualPath(VirtualPathContext context)

    {

        return null;

    }

 

    public Task RouteAsync(RouteContext context)

    {

        context.Handler = this._handler.GetRequestHandler(context.HttpContext, context.RouteData);

 

        return Task.FromResult(0);

    }

}

Routes are added in Startup as well:

app.UseMvc(routes =>

{

    var routeBuilder = routes.MapRoute(

        name: "default",

        defaults: new {},

        template: "{controller=Home}/{action=Index}/{id?}");

 

    routeBuilder.DefaultHandler = new MyRouter();

});

There is already an handler so in this example we are overriding it. You better know what you’re doing if you are going to do something like this!

Route constraints (IRouteConstraint) are still available, just configured in a different way. These allow us to define if a route’s parameter should be matched:

services.Configure<RouteOptions>(options => options.ConstraintMap.Add("my", typeof(MyRouteConstraint)));

And then on the route template attribute we use the constraint:

[Route("home/action/{id:myconstraint}")]

Now there are also conventions (IApplicationModelConvention) that we can use:

public class MyConvention : IApplicationModelConvention

{

    public void Apply(ApplicationModel application)

    {

        //...

    }

}

Registration is done in the AddMvc method too:

services.AddMvc(options => options.Conventions.Insert(0, new MyConvention()));

Configuration

The Web.config file is gone, now configuration is done in a totally different way, preferably through JSON. You can either make the IConfigurationRoot instance available through the services collection:

public IConfigurationRoot Configuration { get; set; }

 

public void ConfigureServices(IServiceCollection services)

{

    //build configuration and store it in Configuration

 

    services.AddSingleton(this.Configuration);

 

    //...

}

or you can build a strongly typed wrapper class for the configuration. For example, for this JSON file:

{

    "ConnectionString": "Data Source=.;Integrated Security=SSPI; Initial Catalog=MyDb",

    "Timeout": 300

}

we could have this code:

class MySettings

{

    public string ConnectionString { get; set; }

    public int Timeout { get; set; }

}

 

public class Startup

{

    public IConfigurationRoot Configuration { get; set; }

    

    public void ConfigureServices(IServiceCollection services)

    {

        services.AddOptions();

        services.Configure<AppSettings>(this.Configuration);

 

        //...

    }

}

 

public MyController : Controller

{

    public MyController(IOptions<AppSettings> appSettings)

    {

        //...

    }

}

Public Folder

Now the public folder is not the same as the project folder: by default, there’s a wwwroot folder below the project folder which is where all the “physical” assets will be copied to at runtime.

Virtual Path Providers

Again, virtual path providers are gone, but there is a similar mechanism. You need to get a hold of the IHostingEnvironment instance and use or change its ContentRootFileProvider or WebRootFileProvider properties. There’s a new file provider interface, IFileProvider, that you can leverage to provide your own behavior:

public class MyFileProvider : IFileProvider

{

    public IDirectoryContents GetDirectoryContents(string subpath)

    {

        //...

    }

 

    public IFileInfo GetFileInfo(string subpath)

    {

        //...

    }

 

    public IChangeToken Watch(string filter)

    {

        //...

    }

}

If you do not wish to or cannot implement one of the IDirectoryContents, IFileInfo or IChangeToken, just return null.

The difference between ContentRootFileProvider and WebRootFileProvider is that the first is used for files inside IHostingEnvironment.ContentRootPath and the latter for those inside IHostingEnvironment.WebRootPath.

OWIN

MVC Core is now based on the OWIN standard, which means you can add your own middleware to the pipeline. This replaces both HTTP Modules and HTTP Handlers. OWIN middleware sits on the pipeline, like this:

public class MyMiddleware

{

    private readonly RequestDelegate _next;

 

    public MyMiddleware(RequestDelegate next)

    {

        this._next = next;

    }

 

    public async Task Invoke(HttpContext context)

    {

        await context.Response.WriteAsync("Hello from a middleware class!");

        await this._next.Invoke(context);

    }

}

We register middleware components in the IApplicationBuilder instance:

app.UseMiddleware<MyMiddleware>();

A middleware class is just a simple POCO class that follows two conventions:

  • The constructor receives a RequestDelegate instance
  • It has an Invoke method taking an HttpContext and returning a Task

The constructor can also take any service that is registered in the service provider. Pay attention, the order by which we add add our middleware has importance. Make sure you add yours soon enough to encapsulate whatever logic you wish to wrap.

Logging and Tracing

Logging and tracing is now only supported as part of the new unified logging framework. You can also write your own middleware that wraps the MVC processing and add your own logging logic. You gain access to the ILoggerFactory or ILogger/ILogger<T> instances through the service provider or using Dependency Injection:

public class MyController : Controller

{

    public MyController(ILogger<MyController> logger)

    {

    }

}

Custom Errors

The custom errors setting is also gone. In order to have similar behavior, enable developer exception page in the Startup class.

Controllers and Views

Controllers stay the same with one addition: we can have POCO controllers, that is, controllers that do not inherit from a base class (other than Object, that is). In order to make proper use of them, for example, if we want to access the context, we need to inject some properties into the controller class – the HttpContext.Current property is no more:

public class HomeController// : Controller

{

    //automatically injected

    [ActionBindingContext]

    public ActionBindingContext BindingContext { get; set; }

 

    //automatically injected

    [ViewDataDictionary]

    public ViewDataDictionary ViewData { get; set; }

 

    //automatically injected

    [ActionContext]

    public ActionContext ActionContext { get; set; }

 

    //constructor-set

    public IUrlHelper Url { get; private set; }

 

    public dynamic ViewBag

    {

        get { return new DynamicViewData(() => this.ViewData); }

    }

 

    public HomeController(IServiceProvider serviceProvider)

    {

        this.Url = serviceProvider.GetService(typeof(IUrlHelper)) as IUrlHelper;

    }

}

The serviceProvider instance will come from the ASP.NET MVC Core dependency injection mechanism.

In views, we now only have the Razor engine. We can now inject components into views:

@inject IMyClass MyClass

 

@MyClass.MyMethod()

and also define functions in the markup:

@functions {

    string MyMethod() {

        return "Something";

    }

}

Another new thing is the _ViewImports.cshtml file. Here we can specify stuff that will apply to all views. The following directives are supported:

  • addTagHelper
  • removeTagHelper
  • tagHelperPrefix
  • using
  • model
  • inherits
  • inject

Layouts files stay the same.

On the other hand, mobile views no longer exist. Of course, you can add logic to find if the current browser is mobile and then serve an appropriate view. Again, the Browser and IsMobileDevice properties are now gone (with the browser capabilities database), so you will have to do your own sniffing.

You can still add view engines (currently, only Razor is supported), you do that when you register MVC services (no more ViewEngines.Engines property):

services

    .AddMvc()

    .AddViewOptions(x =>

        {

            x.ViewEngines.Add(new MyViewEngine());

        });

Model validation providers used to be extensible through the IClientValidatable interface. Now, we have IClientModelValidatorProvider, and we need to add our providers to a collection also when we register MVC services:

services

    .AddMvc()

    .AddViewOptions(x =>

        {

            x.ClientModelValidatorProviders.Add(new MyClientModelValidationProvider());

        });

A client model validation provider needs to implement IClientModelValidatorProvider:

public class MyClientModelValidationProvider : IClientModelValidatorProvider

{

    public void CreateValidators(ClientValidatorProviderContext context)

    {

        //...

    }

}

Finally, views now cannot be precompiled. In the early days of ASP.NET MVC Core, it was possible to precompile them, but not anymore.

Filters

There is no longer a static property for holding the global filers (GlobalFilters.Filters), instead, they can be added to the services collection, normally through the AddMvc overload that takes a lambda:

services.AddMvc(mvc =>

{

    mvc.Filters.Add(typeof(MyActionFilter));

});

Of course, it is still possible to scope filters at the class or method level, using either an attribute inheriting from a *FilterAttribute class (like ActionFilterAttribute) or using TypeFilterAttribute, for dependency injection.

View Components and Tag Helpers

These are new in Core 1. I wrote about View Components here and on Tag Helpers here, so I’m not delving into it again. Two very welcome additions indeed!

Bundling

In the old days, you would normally use the Microsoft ASP.NET Web Optimization package to bundle and minify your JavaScript and CSS files. Now, by default, Gulp is used for that purpose. You can also use BundleMinifier.Core from Mads Kristensen, this needs to be added as a tool and configured through a bundleconfig.json file. BundleMinifier is installed by default starting with Visual Studio 2015 Tooling Preview 1.

Maintaining State

In pre-Core days, one could store state in the Application, which would be available to all requests. Unfortunately, this led to several problems, and the application storage was dropped. Of course, it is still possible to use static members and classes.

Likewise, the Cache storage was also dropped, this time in favor of a more flexible and extensible mechanism. You’ll need the Microsoft.Extensions.Caching.Abstractions Nuget package for the base contracts plus a specific implementation (see Memory or Redis, for example):

public void ConfigureServices(IServiceCollection services)

{

    services.AddDistributedMemoryCache();

 

    //...

}

 

public class MyController : Controller

{

    public MyController(IDistributedCache cache)

    {

        //...

    }

}

Sessions are still around, but they need to be explicitly configured. You need to add a reference to the Microsoft.AspNetCore.Session package, and then register the services and middleware (a distributed memory cache is also required):

public void ConfigureServices(IServiceCollection services)

{

    services.AddDistributedMemoryCache();

    services.AddSession();

}

 

public void Configure(IApplicationBuilder app)

{

    app.UseSession();

    app.UseMvc();

}

 

After this, the ISession instance can be accessed through the HttpContext instance exposed, for example, by the Controller class.

There is no longer support for automatically storing the session in a SQL Server database or the ASP.NET State Service, but it is possible to use Redis, a very popular distributed cache technology.

Publishing

Publish profiles are still around, but now you have other options, such as deploy to Docker. There’s also the dotnet publish command, which places all deployable artifacts in a folder, ready to be copied to the server.

Conclusion

You can see that even though this is still MVC, a lot has changed. In my next post, I will talk a bit about some of the new interfaces that were introduced. In the meantime, hope this gets you up and running! Do let me know if I skipped something or you wish to know more about this. Your feedback is always greatly appreciated!

ASP.NET MVC Core: The Good Parts

MVC 6 should be out any day, so we need to be prepared.

The good thing is, it’s all very similar to MVC 5; the even better thing is, it got better! A couple of ways it is so cool, in my mind, are:

  • Most of the stuff is very similar to what we had: controllers, views, mostly work the same way;
  • MVC and Web API have been merged together, so it’s not really any different add an API controller that returns JSON or an MVC controller that returns an HTML view;
  • All of its code is available in GitHub, and you can even contribute to it;
  • It is now cross-platform, meaning, you will be able to deploy your web app to Linux (even as a Docker container) and Mac (if you use .NET Core);
  • It is very modular: you only add to your project the Nuget packages you really need;
  • It now uses service providers to resolve all of its features; you do not need to know the static location of properties, like, ControllerBuilder.Current, GlobalFilters.Filters, etc; the boilerplate configuration in the Startup class is pretty easy to follow and change;
  • The default template has Bower, NPM and Gulp support out of the box;
  • No need to explicitly add attribute routing, it is built-in by default;
  • We have a better separation of contents and code, in the form of the wwwroot folder to which servable contents are moved;
  • Logging is injected, as are most of the services we need, or we can easily add our own without the need to add any IoC library; even filters can come from IoC;
  • It is now possible to have our Razor pages inherit from a custom class, have custom functions defined in Razor (by the way, do not use it!) and inject components into it;
  • View components and tag helpers are a really cool addition;
  • The new OWIN-based pipeline that is now ASP.NET is much more extensible and easy to understand than System.Web-based ASP.NET used to be;
  • This one is a corollary from the latter: Web.config is gone; let’s face it, it was a big beast, so it’s better to just drop it.

On the other hand, we will need to learn a lot of new stuff, namely, a whole lot of new interfaces and base classes to use. Also, it may sometimes be a bit tricky to find out which Nuget package contains that specific API we’re after. And because there is no more System.Web, all of the infrastructure management is very different. Finally, not all the libraries we’re used to will be immediately available for .NET Core, but that’s really not a problem with ASP.NET Core itself.

All in all, I think it is a good thing! I’ll be talking more on ASP.NET Core, so stay tuned!