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!

Getting the Weather Forecast Using SharePoint Workflows

Introduction

I already wrote a post on how to use SharePoint 2013 workflows. This time, I’ll get back to this topic, with a slightly more interesting (IMO) use case: a recurring workflow that runs once a day and emails users the weather forecast for the next day!

Let’s get started! This will work on both SharePoint 2013 on premises or SharePoint Online.

Weather Forecast

I needed a web service for retrieving the weather forecast that was:

  • Free (of course!)
  • REST (not SOAP!)
  • Using JSON (not XML!)

I ended up using Yahoo’s excellent weather web service. It does all this and a lot more, and I suggest you have a look at it.

image

I had to find out the WOEID for the city I was interested in – Coimbra, Portugal, of course – which was as simple as running this YQL query:

select woeid from geo.places(1) where text="coimbra, pt"

Then, all I had to do was pass the returned value (739672) to the query passed in the query string of the REST web service:

https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%3D%20739672&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys

The result is this:

image

Or, in a formatted way, much easier to read:

{

   "query": {

      "count": 1,

      "created": "2016-05-14T10:13:08Z",

      "lang": "en-US",

      "results": {

         "channel": {

            "units": {

               "distance": "mi",

               "pressure": "in",

               "speed": "mph",

               "temperature": "F"

            },

            "title": "Yahoo! Weather - Coimbra, Coimbra, PT",

            "link": "http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-739672/",

            "description": "Yahoo! Weather for Coimbra, Coimbra, PT",

            "language": "en-us",

            "lastBuildDate": "Sat, 14 May 2016 11:13 AM WEST",

            "ttl": "60",

            "location": {

               "city": "Coimbra",

               "country": "Portugal",

               "region": " Coimbra"

            },

            "wind": {

               "chill": "57",

               "direction": "325",

               "speed": "7"

            },

            "atmosphere": {

               "humidity": "90",

               "pressure": "1004.0",

               "rising": "0",

               "visibility": "16.0"

            },

            "astronomy": {

               "sunrise": "6:17 am",

               "sunset": "8:43 pm"

            },

            "image": {

               "title": "Yahoo! Weather",

               "width": "142",

               "height": "18",

               "link": "http://weather.yahoo.com",

               "url": "http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif"

            },

            "item": {

               "title": "Conditions for Coimbra, Coimbra, PT at 10:00 AM WEST",

               "lat": "40.194672",

               "long": "-8.40737",

               "link": "http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-739672/",

               "pubDate": "Sat, 14 May 2016 10:00 AM WEST",

               "condition": {

                  "code": "26",

                  "date": "Sat, 14 May 2016 10:00 AM WEST",

                  "temp": "57",

                  "text": "Cloudy"

               },

               "forecast": [

                  {

                     "code": "39",

                     "date": "14 May 2016",

                     "day": "Sat",

                     "high": "61",

                     "low": "54",

                     "text": "Scattered Showers"

                  },

                  {

                     "code": "28",

                     "date": "15 May 2016",

                     "day": "Sun",

                     "high": "71",

                     "low": "54",

                     "text": "Mostly Cloudy"

                  },

                  {

                     "code": "30",

                     "date": "16 May 2016",

                     "day": "Mon",

                     "high": "76",

                     "low": "52",

                     "text": "Partly Cloudy"

                  },

                  {

                     "code": "28",

                     "date": "17 May 2016",

                     "day": "Tue",

                     "high": "77",

                     "low": "53",

                     "text": "Mostly Cloudy"

                  },

                  {

                     "code": "30",

                     "date": "18 May 2016",

                     "day": "Wed",

                     "high": "78",

                     "low": "52",

                     "text": "Partly Cloudy"

                  },

                  {

                     "code": "30",

                     "date": "19 May 2016",

                     "day": "Thu",

                     "high": "77",

                     "low": "52",

                     "text": "Partly Cloudy"

                  },

                  {

                     "code": "30",

                     "date": "20 May 2016",

                     "day": "Fri",

                     "high": "71",

                     "low": "55",

                     "text": "Partly Cloudy"

                  },

                  {

                     "code": "28",

                     "date": "21 May 2016",

                     "day": "Sat",

                     "high": "72",

                     "low": "55",

                     "text": "Mostly Cloudy"

                  },

                  {

                     "code": "30",

                     "date": "22 May 2016",

                     "day": "Sun",

                     "high": "72",

                     "low": "53",

                     "text": "Partly Cloudy"

                  },

                  {

                     "code": "30",

                     "date": "23 May 2016",

                     "day": "Mon",

                     "high": "75",

                     "low": "52",

                     "text": "Partly Cloudy"

                  }

               ],

               "description": "<![CDATA[<img src=\"http://l.yimg.com/a/i/us/we/52/26.gif\"/>\n<BR />\n<b>Current Conditions:<\/b>\n<BR />Cloudy\n<BR />\n<BR />\n<b>Forecast:<\/b>\n<BR /> Sat - Scattered Showers. High: 61Low: 54\n<BR /> Sun - Mostly Cloudy. High: 71Low: 54\n<BR /> Mon - Partly Cloudy. High: 76Low: 52\n<BR /> Tue - Mostly Cloudy. High: 77Low: 53\n<BR /> Wed - Partly Cloudy. High: 78Low: 52\n<BR />\n<BR />\n<a href=\"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-739672/\">Full Forecast at Yahoo! Weather<\/a>\n<BR />\n<BR />\n(provided by <a href=\"http://www.weather.com\" >The Weather Channel<\/a>)\n<BR />\n]]>",

               "guid": {

                  "isPermaLink": "false"

               }

            }

         }

      }

   }

}

SharePoint Workflow

Next, I wanted to use this information in a SharePoint workflow. This workflow has to run every day automatically, and this was a challenge, because it is not supported out of the box. But, first things first, let’s see how I designed it the Weather Forecast workflow.

Initialization

Open SharePoint Designer and create a new Site workflow, make sure it is using the SharePoint 2013 settings. I first added a stage called Initialization, where I created a string workflow variable named url, to which I assigned the web service URL:

image

Next, I also created a dictionary variable named requestHeaders, to which I added a string entry called Accept, with value application/json (I don’t think this is necessary, but it is always good to tell a REST web service what we’re expecting):

image

Get Weather Forecast

On a new stage named Get Weather Forecast, I add the call to the web service itself, by adding a Call HTTP Web Service action, pointing to the contents of the url variable:

image

After I do that, I access the properties of Call HTTP Web Service action and I set the request headers as coming from the requestHeaders variable I just created:

image

Make sure you set the response to go to a new dictionary variable, responseContent. The rest is really irrelevant, but if you run into problems, it may be useful to look at the responseCode (string) and responseHeaders (dictionary) variables.

Process Response

I then added a new stage named Process Response, where I added an action of type Get an Item from a Dictionary, from which I extracted value query/results/channel/item/forecast(1)/text from the responseContent variable, which contains the result of the web service invocation, into a new string variable called result:

image

This needs some explanation. The value I’m extracting from dictionary is similar to a JSONPath – the JavaScript dotted-path to traverse an object – with two differences:

  • Instead of dots (.), we use slashes (/)
  • Instead of square brackets ([]) for indexed properties, we use parenthesis

The path we are extracting is so that we can jump directly to the textual description of the forecast for the next day, according to the schema that the Yahoo web service returns. If you use another one, you will need to change this path, of course.

Send Email

The next stage I added is called Send Email, and it’s where I send the weather forecast to the interested users. In it, I add a single action of type Send an Email,

image

In the To field, we should use a group instead of explicitly named users, something like “Weather Forecast Users”. In the body of the email, I have a mix of text and the result variable, which, if you remember, contains the portion of the web service response that has the textual description of the forecast.

Sleep for a Day

The last stage I’m adding is called Sleep for a Day, and, again, only has a single activity, Pause for Duration, configured to sleep for 1 day.


Wrap Up

This is what the resulting workflow looks like:

imageIn each stage, we need to add a transition to the next one, except in Sleep for a Day, on which the transition is going to Initialization. So, I have the following stages and transitions:

Stage Transition
Initialization Get Weather Forecast
Get Weather Forecast Process Response
Process Response Send Email
Send Email Sleep for a Day
Sleep for a Day Initialization

As for variables, I have:

image

Starting the Workflow

Now, all we have to do is, after publishing the workflow, is starting it. We do that through Site contentsSite workflows, normally available at URL /_layouts/15/workflow.aspx, and clicking the Weather Forecast link.

image

This workflow, it should be noted, shouldn’t stop, because after it reaches the final stage, it jumps to the first one, don’t forget about it.

Debugging the Workflow

The debugging experience is not great. What you can do is log stuff to the workflow history, using a Log to History List action, but be warned that you cannot log large contents: for example, logging the result of the web service call won’t work. What you can do is see where the workflow stopped and see if any exception was thrown, by clicking at the Status field of the running or completed workflow and inspecting the messages produced:

image

You also have the Workflow Health page (/_layouts/15/WorkflowServiceHealth.aspx), on which you can also see some information and stop running workflows that have gone rogue:

image

It is also worth pointing out that, unless you configured it otherwise, the output history for the workflows is stored in a hidden list called Workflow History (/Lists/Workflow%20History/AllItems.aspx):

image

Conclusion

SharePoint offers some mechanisms for integrating outside data, in the form of REST web services returning JSON, into workflows. While more complex scenarios require more advanced techniques and APIs (Business Connectivity Services, for example, or custom workflow actions), it is still possible to do some interesting stuff with what is available out of the box. Variations to this example might include conditional checks, like, only sending a warning email if the weather forecast is not good, or store the results for the next days, etc. I leave that as an exercise to you, dear reader! Smile In the meantime, do let me know how it goes!

ASP.NET Core Inversion of Control and Dependency Injection

Introduction

There are quite a few good posts out there on Inversion of Control (IoC) and Dependency Injection (DI) in the ASP.NET Core world, but I felt there was still something to be said, hence this post! Mind you, this is going to be a long one! I once wrote another post on the history of dependency resolution in .NET, you may want to have a look at it. Always keep in mind that this is based on the latest bits, and may still change when it gets to the final version.

Services Registration

At bootstrap, ASP.NET Core will either call the ConfigureServices method, or one with a name following the convention Configure<environment>Services, where <environment> comes from the Hosting:Environment environment variable, and you can also set it in Visual Studio:

image

It is commonly set to “Development”, “Production”, “Staging”, etc. Keep in mind that if the environment-specific method exists (e.g., ConfigureDevelopmentServices), then the generic one (ConfigureServices) is not called.

The Configure*Services method is passed an instance of IServiceCollection, which is where we get to store our service registrations, so that they can be used by ASP.NET Core further along the pipeline. A service registration needs three things:

  • A key type, normally an interface or an abstract base class;
  • A concrete implementation of the key type;
  • A lifetime.

The lifetime determines how many times the concrete implementation is going to be built. The ASP.NET Core service provider implementation knows about three different lifetimes:

  • Scoped: an instance is created the first time it is requested during the same HTTP request, and during that request, this same instance is always returned;
  • Singleton: an instance is created the first time it is requested, and this same instance is always returned in all subsequent calls;
  • Transient: a new instance is always created, whenever it is requested.

A registration is an instance of the ServiceDescriptor class that is added to the IServiceCollection instance:

services.Add(new ServiceDescriptor(typeof(IMyService), typeof(MyService), ServiceLifetime.Singleton));

There are several extension methods that make this registration even easier.

What if you want to have custom processing when a service is returned? Simple:

services.AddTransient<IMyService>(sp =>

{

    var something = sp.GetService(typeof(ISomething)) as ISomething;

    var other = new OtherService();

    //do something with it

    return new MyService(other);

});

Keep in mind that the concrete service must either implement or inherit from the key service. Also, for the Scoped lifetime, if the concrete class implements IDisposable, the service provider will honor it and call Dispose at the end of the HTTP request.

After Configure*Services, ASP.NET Core calls Configure, also in the Startup class. This is where the core initialization occurs, like, adding all middleware, such as the MVC one, that makes the application works the way we expect it. The Configure method can either have no parameters or it can receive one or more parameters with types that match the registered services. For example, we will always have IApplicationBuilder, IHostingEnvironment, ILoggerFactory, so we can add them as parameters together with our own:

public void Configure(

    IApplicationBuilder app,

    IHostingEnvironment env,

    ILoggerFactory loggerFactory,

    IMyService service)

{

    //do something with the services

}

It gives us a good chance to initialize them before the actual fun begins. If we want, we can also pass it just an instance of the dependency resolution service, represented by the IServiceProvider interface, which has been around since the early days of .NET. The ASP.NET Core service provider implements this interface, so having it here just means: “get me the service provider implementation so that I can retrieve services from it”:

public void Configure(IServiceProvider serviceProvider)

{

    var env = serviceProvider.GetService(typeof(IHostingEnvironment)) as IHostingEnvironment;

    var service = serviceProvider.GetService(typeof(IMyService)) as IMyService;

}

In the latest version of ASP.NET Core, there is no globally accessible reference to the built-in service provider, something known as the service locator, of bad reputation. If, for any reason you feel you need it, here is the place to store it. By the way, the Microsoft.Extensions.DependencyInjection package has some good strongly typed extension methods for IServiceProvider, make sure you include it.

Services

Each concrete service class itself can be dependency-injected: by default, it should be a concrete class and have a public parameter-less constructor; if, however, we want to inject dependencies into it, which also need to be registered in the service provider, we can have a constructor that takes these dependencies:

public class MyService : IMyService

{

    public MyService(IServiceProvider serviceProvider)

    {

        //get something from the service provider

    }

}

Notice the usage of IServiceProvider again. Another option is to have the constructor contain more concrete dependencies:

public class MyService : IMyService

{

    public MyService(ILoggerFactory loggerFactory)

    {

        //do something with the logger factory

    }

}

You can pass any number of parameters, of any type that is registered in the service provider, normally in one of the Configure*Services methods. If the specified service type is not registered, you get an exception at runtime.

Controllers

An MVC controller can have dependencies injected through its constructor, like I’ve shown for services:

public class HomeController : Controller

{

    public HomeController(IMyService service)

    {

        //do something with the service

    }

}

The same pattern applies: we can either declare a parameter as IServiceProvider or as a more specific type. It doesn’t matter if our controller inherits from Controller or is a POCO controller.

There was another dependency injection possibility with MVC controllers, which consisted in decorating public properties with a [FromServices] attribute: if a registration exists that matched the property’s type, it would be injected into the property just after the controller is constructed:

public class HomeController

{

    [FromServices]

    public IService Service { get; set; }

}

This is no longer possible, and the functionality was removed in DNX RC2, although it will still work in RC1. Forget about it.

By default, controller classes themselves do not come from the dependency resolution mechanism. You can achieve that, if, in Configure*Services, you call AddControllersAsServices, passing it either a Type or an Assembly collection:

services

    .AddMvc()

    .AddControllersAsServices(new[] { typeof(HomeController).GetTypeInfo().Assembly });

This allows you to do this:

services.AddSingleton<HomeController, SingletonHomeController>();

Each time MVC tries to build an HomeController, it will instead get the same SingletonHomeController. Note that I am not saying that you should do this, but I think you get the idea!

Filters

Filters in MVC allow you to intercept action method calls, results and exceptions, and do stuff before, after of instead of the real actions. You have global filters and attribute filters: global filters apply always, and attribute filters only apply in the scope where they are declared – a controller’s class or an action method. Filters themselves can have dependencies injected into them.

In order to declare global filters, you use one of the overloads of the AddMvc method, normally in the Configure*Services method, and registering the filter as a service:

services.AddMvc(mvc => mvc.Filters.AddService(typeof(GlobalFilter)));

MVC will try to resolve the filter type, if necessary, injecting it any dependencies, in the usual way:

public class GlobalFilter : IActionFilter

{

    public GlobalFilter(IMyService service)

    {

        //do something with the service

    }

 

    public void OnActionExecuted(ActionExecutedContext context)

    {            

    }

 

    public void OnActionExecuting(ActionExecutingContext context)

    {

    }

}

The other option for filters is attributes, but attributes require a public parameter-less constructor. The MVC team came up with an alternative for that, in the form of the ServiceFilterAttribute and TypeFilterAttribute attributes. Both receive a Type and the difference is that the first will try to resolve that type from the services registration and the last one will just instantiate it. Let’s see an example:

[ServiceFilter(typeof(GlobalFilter))]

public class HomeController : Controller

{

    [TypeFilter(typeof(SomeFilter))]

    public IActionResult Index()

    {

        //...

    }

}

So, GlobalFilter is retrieved from the services registration, and, if it is a filter, it will behave accordingly to the context where it is located, in this case, it is the whole controller. SomeFilter, on the other hand, is just instantiated and used, no need to have it registered. Don’t forget that types passed to ServiceFilterAttribute and TypeFilterAttribute have to implement one of the filter interfaces in namespace Microsoft.AspNet.Mvc.Filters otherwise an exception is thrown.

Models

Model classes are declared as parameters to action methods in an MVC controller. There’s a binding mechanism that fills their properties automatically, but we can also use dependency injection here.

First, the whole model can come from dependency injection:

public IActionResult Index([FromServices] IMyService service)

{

    //...

}

Or, at least, some properties of the model:

public IActionResult Update(Model model)

{

    //...

}

 

public class Model

{

    [FromServices]

    public IMyService Service { get; set; }

 

    //...

}

Views

MVC views can also take injected services, through the @inject directive:

@inject IMyService service;

 

<p>@service.Serve()</p>

View Components

View components, introduced in ASP.NET MVC Core, can also be injected in pretty much the same way as controllers:

public class MyServiceViewComponent : ViewComponent

{

    public MyServiceViewComponent(IMyService service)

    {

        //do something with the service

    }

    

    public string Invoke()

    {

        //...

    }

}

Tag Helpers

Tag helpers, like view components and controllers, also support constructor injection:

[HtmlTargetElement("service")]

public class ServiceTagHelper : TagHelper

{

    public ServiceTagHelper(IMyService service)

    {

        //do something with the service

    }

 

    public override void Process(TagHelperContext context, TagHelperOutput output)

    {

        //...

    }

}

Middleware

OWIN-style middleware are likewise injectable through the constructor:

public class ServiceMiddleware

{

    private readonly RequestDelegate _next;

    

    public ServiceMiddleware(RequestDelegate next, IMyService service)

    {

        this._next = next;

        //do something with the service

    }

    

    public Task Invoke(HttpContext httpContext)

    {

        //...

    }

}

Using a Custom IoC/DI Container

Now, you may not want to use the built-in service provider and use your own (Unity, Autofac, Ninject, TinyIoC, etc). That is certainly possible!

You need to change the signature of the Configure*Services method so as to return an IServiceProvider:

public IServiceProvider ConfigureServices(IServiceCollection services)

{

    services.AddMvc();

 

    services.AddTransient<IMyService, MyService>();

 

    return new MyIoCContainer(services.BuildServiceProvider());

}

The key here is to create an instance of the service provider we want to use, maybe leveraging on the one produced from the service collection (BuildServiceProvider method), and return it here. Of course, if it has more features and lifetimes than the default one, you are free to use them all. The only contract it has to comply to is that of IServiceProvider.

Dependency Resolution

While running your MVC application, you can explicitly ask for services registered in the global (the default or your own) service provider. The HttpContext class exposes a RequestServices property; here you will find the custom service provider that you returned in Configure*Services, or ASP.NET Core’s built-in one. Whenever you have a reference to the current HttpContext (controllers, view components, tag helpers, views, middleware, filters), you get it as well. The “old” ApplicationServices was removed in recent commits, so it won’t make it to the final version of ASP.NET Core and you shouldn’t be using it.

Conclusion

The dependency injection mechanism was substantially changed in ASP.NET Core. The only identical feature seems to be constructor injection, and it is understandable, since it’s what most people should be using anyway. Now every moving part of ASP.NET Core is injectable through the same mechanism, which I think is a good thing. The problems so far have been the relative instability in the ASP.NET Core, things have been changing a lot, and there is still no light at the end of the tunnel.

Payloads as dynamic Objects in ASP.NET MVC

Even though the dynamic type seems to be everywhere these days, ASP.NET MVC still doesn’t support having dynamic parameters in controller action methods out of the box; which is to say, this doesn’t work as expected:

[HttpPost]

public ActionResult Post(dynamic payload)

{

    //payload will be an object without any properties

 

    return this.View();

}

However, because MVC is so extensible, it is very easy to achieve it. For that, we need to build a custom model binder and apply it to our action method parameter. We’ll assume that the content will come as JSON from the HTTP POST payload. Note that this does not happen with Web API, but still happens with MVC Core!

There are a couple of ways by which we can bind a model binder to a parameter:

First, let’s focus on the actual model binder, the core for any of the above solutions; we need to implement the IModelBinder interface, which isn’t really that hard to do:

public sealed class DynamicModelBinder : IModelBinder

{

    private const string ContentType = "application/json";

 

    public DynamicModelBinder(bool useModelName = false)

    {

        this.UseModelName = useModelName;

    }

 

    public bool UseModelName { get; private set; }

 

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

    {

        dynamic data = null;

 

        if ((controllerContext.HttpContext.Request.AcceptTypes.Any(x => x.StartsWith(ContentType, StringComparison.OrdinalIgnoreCase) == true) &&

            (controllerContext.HttpContext.Request.ContentType.StartsWith(ContentType, StringComparison.OrdinalIgnoreCase) == true)))

        {

            controllerContext.HttpContext.Request.InputStream.Position = 0;

 

            using (var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream))

            {

                var payload = reader.ReadToEnd();

 

                if (string.IsNullOrWhiteSpace(payload) == false)

                {

                    data = JsonConvert.DeserializeObject(payload);

 

                    if (this.UseModelName == true)

                    {

                        data = data[bindingContext.ModelName];

                    }

                }

            }

        }

 

        return data;

    }

}

Nothing fancy here; it will check to see if both the Accept and the Content-Type HTTP headers are present and set to application/json, the official MIME type for JSON, before parsing the posted content. If any content is present, JSON.NET will parse it into it’s own object. The UseModelName property is used to bind to a specific property of the payload, for example, say you are binding to a parameter called firstName, and you want it populated with the contents of the firstName field in the payload. In our case, we don’t need it, we want the whole thing, so it is set to false.

Now, the way I recommend for applying this model binder is through a custom attribute:

[Serializable]

[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]

public sealed class DynamicModelBinderAttribute : CustomModelBinderAttribute

{

    public DynamicModelBinderAttribute(bool useModelName = false)

    {

        this.UseModelName = useModelName;

    }

 

    public bool UseModelName { get; private set; }

 

    public override IModelBinder GetBinder()

    {

        return new DynamicModelBinder(this.UseModelName);

    }

}

It goes like this:

[HttpPost]

public ActionResult Post([DynamicModelBinder] dynamic payload)

{

    //payload will be populated with the contents of the HTTP POST payload

 

    return this.View();

}

Or, if you want to do it for several dynamic parameters, just set a global model binder provider for type Object; this is safe, because we would never have a parameter of type Object:

public sealed class DynamicModelBinderProvider : IModelBinderProvider

{

    public static readonly IModelBinderProvider Instance = new DynamicModelBinderProvider();

 

    public IModelBinder GetBinder(Type modelType)

    {

        if (modelType == typeof (object))

        {

            return new DynamicModelBinder();

        }

 

        return null;

    }

}

And we register is as this:

ModelBinderProviders.BinderProviders.Insert(0, DynamicModelBinderProvider.Instance);

And that’s it. This is one of what I consider to be ASP.NET MVC flaws, and they will deserve another post, soon. Web API already solves this problem, but it is still there in the future version of MVC Core, and can be solved in the same way.

Encrypted JavaScript in ASP.NET MVC Core

To complete the Data URI saga, here is another technique that you may find interesting: this time, it’s about encrypting JavaScript contents, so as to make them more difficult to tamper with.

Data URIs can be used for serving any content that would normally come from an external resource, such as a JavaScript/CSS file or an image. What we will do here is, using ASP.NET MVC Core’s Tag Helpers, we get hold of the JavaScript that is defined inside a SCRIPT tag and we turn into a Data URI. Pretty simple, yet the result is also pretty cool!

Show me the code, I hear you say:

[HtmlTargetElement("script")]

[HtmlTargetElement("script", Attributes = "asp-encrypt")]

[HtmlTargetElement("script", Attributes = "asp-src-include")]

[HtmlTargetElement("script", Attributes = "asp-src-exclude")]

[HtmlTargetElement("script", Attributes = "asp-fallback-src")]

[HtmlTargetElement("script", Attributes = "asp-fallback-src-include")]

[HtmlTargetElement("script", Attributes = "asp-fallback-src-exclude")]

[HtmlTargetElement("script", Attributes = "asp-fallback-test")]

[HtmlTargetElement("script", Attributes = "asp-append-version")]

public class InlineScriptTagHelper : ScriptTagHelper

{

    public InlineScriptTagHelper(ILogger<ScriptTagHelper> logger, IHostingEnvironment hostingEnvironment,

        IMemoryCache cache, IHtmlEncoder htmlEncoder, IJavaScriptStringEncoder javaScriptEncoder,

        IUrlHelper urlHelper) : base(logger, hostingEnvironment, cache, htmlEncoder, javaScriptEncoder, urlHelper)

    {

    }

 

    [HtmlAttributeName("asp-encrypt")]

    public bool Encrypt { get; set; }

 

    public override void Process(TagHelperContext context, TagHelperOutput output)

    {

        if ((this.Encrypt == true) && (string.IsNullOrWhiteSpace(this.Src) == true))

        {

            var content = output.GetChildContentAsync().GetAwaiter().GetResult().GetContent();

            var encryptedContent = Convert.ToBase64String(Encoding.ASCII.GetBytes(content));

            var script = $"data:text/javascript;base64,{encryptedContent}";

 

            output.Attributes.Add("src", script);

            output.Content.Clear();

        }

 

        base.Process(context, output);

    }

}

You can see that this tag helper inherits from ScriptTagHelper, which is the OOTB class that handles SCRIPT tags. Because of this inheritance, we need to add all the HtmlTargetElementAttributes, so that all the rules get applied properly. For this one, we need to add an extra rule, which forces the SCRIPT tag to have an asp-encrypt attribute.

So, say you have this in your Razor view:

<script asp-encrypt="true">
   1:  

   2:     window.alert('hello, world, from an encrypted script!');

   3:  

</script>

What you’ll end up with in the rendered page is this:

<script src="data:text/javascript;base64,DQoNCiAgICB3aW5kb3cuYWxlcnQoJ2hlbGxvLCB3b3JsZCwgZnJvbSBhbiBlbmNyeXB0ZWQgc2NyaXB0IScpOw0KDQo="></script>

Cool, wouldn’t you say? Of course, no JavaScript that runs on the client can ever be 100% secure, and you should always keep that in mind. But for some purposes, it does pretty well! Winking smile

Inline Images in ASP.NET MVC Core

I have blogged extensively about Data URIs in the past. It allows us to render external contents inside of the page’s HTML, avoiding additional HTTP requests, but enlarging the HTML to serve. Sometimes, it does make sense, especially because the whole page can be made cacheable.

MVC does not offer any mechanism for serving images as inline Data URIs, and that is the reason for this post! Winking smile

For this example, I added an extension method to the IHtmlHelper class, InlineImage:

public static class HtmlHelperExtensions

{

    private static string GetFileContentType(string path)

    {

        if (path.EndsWith(".JPG", StringComparison.OrdinalIgnoreCase) == true)

        {

            return "image/jpeg";

        }

        else if (path.EndsWith(".GIF", StringComparison.OrdinalIgnoreCase) == true)

        {

            return "image/gif";

        }

        else if (path.EndsWith(".PNG", StringComparison.OrdinalIgnoreCase) == true)

        {

            return "image/png";

        }

 

        throw new ArgumentException("Unknown file type");

    }

 

    public static HtmlString InlineImage(this IHtmlHelper html, string path, object attributes = null)

    {

        var contentType = GetFileContentType(path);

        var env = html.ViewContext.HttpContext.ApplicationServices.GetService(typeof (IHostingEnvironment)) as IHostingEnvironment;

 

        using (var stream = env.WebRootFileProvider.GetFileInfo(path).CreateReadStream())

        {

            var array = new byte[stream.Length];

            stream.Read(array, 0, array.Length);

 

            var base64 = Convert.ToBase64String(array);

 

            var props = (attributes != null) ? attributes.GetType().GetProperties().ToDictionary(x => x.Name, x => x.GetValue(attributes)) : null;

 

            var attrs = (props == null)

                ? string.Empty

                : string.Join(" ", props.Select(x => string.Format("{0}=\"{1}\"", x.Key, x.Value)));

 

            var img = $"<img src=\"data:{contentType};base64,{base64}\" {attrs}/>";

 

            return new HtmlString(img);

        }

    }

}

You can see that I only support three image formats: JPEG, GIF and PNG. These are the safe formats that can be rendered by all browsers. The format is inferred from the file name’s extension.

The InlineImage method takes a local file name that will be considered from the site’s root, and an optional collection of attributes. If present, these attributes are added to the generated IMG tag as-is.

To use this extension, all we need is to add this code in a Razor view:

@Html.InlineImage("image.jpg", new { width = "200", height = "200" });

And the output should look like this (trimmed):

<img src="data:image/jpeg;base64,SGVsbG8sIFdvcmxkIQ%3D%3D...=" width="200" height="200" />

This code works as is in ASP.NET MVC Core, but can be easily changed to work in MVC 5 or prior: just use Server.MapPath to get the physical address of the file to load.

MVC Controller Resolver Cache

I recently faced a curious problem: I was using a third party IoC container in an MVC 5 (ASP.NET 4.*) app. In it, I had registered a service with a lifetime of transient, meaning, each resolution would return a different instance.

As you may know, in an MVC controller, there are two ways by which we can resolve a service using the MVC infrastructure:

 

I was using Controller.Resolver to resolve a service, but, after the first resolution, I would alwas get the same instance! It turns out that, by default, Controller.Resolver does not resolve to the same as DependencyResolver.Current, but instead uses an internal implementation that caches resolved services(DependencyResolver.CurrentCache, an internal property)! This means that it is virtually unusable with any lifetime other than singleton!

There are at least three workarounds:

 

If you were to ask me, I’d go for option #3.

ASP.NET 5 Node Services

At the MVP Global Summit, Steven Sanderson (@stevensanderson) presented a Microsoft project he was working on: Node Services. In a nutshell, this is an integration of ASP.NET 5 and Node.js, it makes it possible to call a Node.js function from ASP.NET. One of its possible usages is to use Node.js to compile AngularJS directives or ReactJS JSX files, and for that reason, there are two modules built on top of Node Services just for that purpose (code available at GitHub and NuGet, here and here).

Disclaimer: this is still in early stage, and is likely to change!

So, after you install the NuGet package using the now familiar syntax:

image

You need to register the Node Services it in Startup.cs’s ConfigureServices method:

var app = services.Single(x => x.ServiceType == typeof (IApplicationEnvironment)).ImplementationInstance as IApplicationEnvironment;

 

services.AddSingleton<INodeServices>(new Func<IServiceProvider, INodeServices>(sp => Configuration.CreateNodeServices(NodeHostingModel.Http, app.ApplicationBasePath)));

Now, there are two ways by which ASP.NET can communicate with the Node.js host:

  • HTTP (NodeHostingModel.Http): a local service is started which waits for JSON requests and routes them to Node.js;
  • Interprocess communication (NodeHostingModel.InputOutputStream): a direct stream with the Node.js hosting process; much faster than the HTTP version, but also less reliable.

Creating a Node.js module is easy; let’s add a .JS file to the project:

module.exports = function (cb, a, b)

{

    a = parseInt(a);

    b = parseInt(b);

 

    return cb(null, (a + b).toString());

};

For simplicity’s sake, we are doing a very simple operation: just adding two numbers, but in a real-life scenario you can require any other Node.js modules and do any arbitrarily complex operations. You need to be aware of a couple of things:

  • The first parameter to the exported function must be a callback function; this will be used for returning the result;
  • Each parameter must either be a string or a JSON object;
  • The result – second parameter to the callback function – also needs to be a string or JSON.

And how do you call this? You just need a reference to the registered instance of INodeService, and on it you call a module asynchronously, passing it some parameters:

var node = this.Resolver.GetService(typeof(INodeServices)) as INodeServices;

var result = await node.Invoke<string>("sum.js", "1", "2");    //"3"

You can also specify the module and function name explicitly, if you export it from the .JS file (not in this example):

var result = await node.InvokeExport<string>("sum.js", "sum", "1", "2");

Happy Noding! Winking smile