.NET Core Console Applications

Updated

.NET Core is not just for web apps, and some people tend to forget about it! Well, this post is about that! Smile

OK, let’s first create a “console” .NET Core app. In Visual Studio 2015, create a new project of type WebClass Library (Package):

image

After you do that, if you want to run your app inside VS, you need to change a few things. Go to project.json and change the library from dotnet5.4 to dnxcore50:

image

If you want to get information from the environment, you need to obtain a reference to the APIs that supply that information. So, add references to Microsoft.Extensions.DependencyInjection.Abstractions and Microsoft.Extensions.PlatformAbstractions (you can see that in the above picture).

Now, things get a bit weird… you need to do something rather dumb:

public class Program

{

    public static IServiceProvider ServiceProvider { get; private set; }


    public Program(IServiceProvider serviceProvider)

    {

        ServiceProvider = serviceProvider;

    }


    static void Main(string [] args)

    {

        var re = ServiceProvider.GetService<IRuntimeEnvironment>();        //for operating system, architecture and runtime info

        var ae = ServiceProvider.GetService<IApplicationEnvironment>();    //for application path, name, version, configuration info

    }

}

Some “context” services are available through the dependency injection framework, available as an IServiceProvider instance, but you can also get a pointer to them through the PlatformServices.Detault property:

var ae = PlatformServices.Default.Application;


var re = PlatformServices.Default.Runtime;

Here you will find these services:

  • IApplicationEnvironment: the application context
  • IRuntimeEnvironment: runtime context
  • IAssemblyLoaderContainer: for adding assembly loaders
  • IAssemblyLoadContextAccessor: a façade to the assembly loaders, for loading assemblies on demand
  • ILibraryManager: for introspecting the referenced libraries

You can see that the .NET Core team took the decision to inject these into the constructor of types that it builds, but the funny think is that there is no need for an actual instance of the Program class, as all the runtime needs is the static Main method! It seems a bit silly that we need to keep things in static fields, but I think they do not want to have static access points to these in the core framework, so it’s up to use how we are going to use them. Rest assured, the constructor will be called before Main!

Update: According to a Microsoft announcement here, from RC2 onwards, .NET Core will not support constructor injection in the Program class, so, the way to go will be through PlatformServices and CompilationServices. However, it still works in the DNX 1.0.0-rc2-16357 runtime.

If you need to use System.Console, which you will likely do, in a console, app, you need to add a reference to the System.Console Nuget package, for the dnxcore50 framework.

For more advanced stuff, like, for example, accessing databases – any database as long as it is SQL Server… – you need to add the System.Data.SqlClient Nuget package. The code looks exactly the same as it would in plain old .NET:

using (var con = new SqlConnection())

using (var cmd = con.CreateCommand())

{

    con.ConnectionString = @"Data Source=.\SQLEXPRESS; Integrated Security=SSPI";

    con.Open();


    cmd.CommandText = "SELECT GetUtcDate()";


    var now = (DateTime) cmd.ExecuteScalar();


    Console.WriteLine(now);

}

Finally, you need to add a command to it, so that you can actually run it. Add a command, say, “run”, to the commands section of project.json:

"commands": {

  "run": "My.ConsoleApp"

}

Here, My.ConsoleApp should the name (and folder) of your project, these should match.

And this is about it. If you want to pass parameters to your program, you can do so in the call to dnx, after the command:

dnx run this and that

this and that” will be passed as arguments to the Main method.

For running dnx, make sure your runtime is set appropriately, by using dnvm.

Enjoy .NET Core console! Winking smile

 

Using MEF in .NET Core

For those who don’t know, the Managed Extensibility Framework (MEF) is alive and well, and has been ported to .NET Core as Microsoft.Composition (source here). Not all of MEF has been ported, just MEF 2 (System.Composition), not MEF 1 (System.ComponentModel.Composition), meaning, we don’t have the catalogs, which included, among others, the ability to load types from assemblies in a directory.

Using MEF is straightforward, and this time I will not go into details. What I will show is how we can load types from files in a directory.

First, a sample usage might be:

var conventions = new ConventionBuilder();

conventions

    .ForTypesDerivedFrom<IPlugin>()

    .Export<IPlugin>()

    .Shared();

 

var assemblies = new[] { typeof(MyPlugin).GetTypeInfo().Assembly };

 

var configuration = new ContainerConfiguration()

    .WithAssemblies(assemblies, conventions);

 

using (var container = configuration.CreateContainer())

{

    var plugins = container.GetExports<IPlugin>();

}

Notice that we have to build the assemblies list ourselves.

Now, let’s load assemblies from a folder instead. We’ll create an extension method for that purpose:

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 assemblies = Directory

            .GetFiles(path, "*.dll", searchOption)

            .Select(AssemblyLoadContext.GetAssemblyName)

            .Select(AssemblyLoadContext.Default.LoadFromAssemblyName)

            .ToList();

 

        configuration = configuration.WithAssemblies(assemblies, conventions);

 

        return configuration;

    }

}

The key here is the AssemblyLoadContext class: this is what allows us to obtain an assembly from a file stream or a byte array. Notice that in .NET Core, things have changed significantly, and now we don’t have AppDomain or Assembly.LoadFrom, and assemblies are now loaded by an assembly loader, in a similar way to what Java does with class loaders.

So, now you can change the code to:

var path = @"c:\some\path";

 

var configuration = new ContainerConfiguration()

    .WithAssembliesInPath(path, conventions);

It even works for loading assemblies in all sub-folders.

Maybe I’ll write another post on MEF in the near future, so stay tuned!

Measuring Type Distance

Imagine this: you are building an API that uses conventions. A convention applies to a type. There can be several conventions registered, but the API needs to figure out what convention applies to any given class. The problem is, you can have conventions associated with base classes, concrete classes or even interfaces. For example, consider these:

public interface IInterface

{

  //something

}


public abstract class Base : IInterface

{

  //something

}


public class Derived : Base

{

  //something

}

You register one convention for each of these types:


AddConvention<Base>(new SomeConvention());


AddConvention<Derived>(new AnotherConvention());


AddConvention<IInterface>(new YetAnotherConvention());


AddConvention<object>(new EvenAnotherConvention());

And, at some point, you have this:

var convention = FindConventionFor(someObject);

If someObject is of type Derived, AnotherConvention should be returned; if it is of any other class inheriting from Base, it should be SomeConvention; and if it is neither but happens implement IInterface, then the result should be YetAnotherConvention. For any other case, the convention would be EvenAnotherConvention. Of course, the FindConventionFor method should always return the most specific convention that applies to that class.

Another option would be to return all conventions, ordered from more generic to more specific:

var conventions = FindConventionsFor(someObject);

In this case, it would return [ YetAnotherConvention, EvenAnotherConvention, SomeConvention, AnotherConvention ]. Why do we want to order it like this? Well, so that we can apply conventions, starting from the most generic and ending on the most specific.

And now the question is: how do we order the types? Let’s say we have a target type, which is the type of someObject. We can write a method like this one:

public static int Distance(this Type source, Type target)

{

    if (target.IsAssignableFrom(source) == false)

    {

        return int.MaxValue;

    }


    if (source.GetTypeInfo().IsInterface == true)

    {

        return int.MaxValue / 2;

    }


    var current = source;

    var distance = 0;


    while (current != typeof(object))

    {

        if (target == current)

        {

            break;

        }


        current = current.GetTypeInfo().BaseType;

        distance++;

    }


    return distance;

}

Basically, if the types are related, add 1 per each inheritance level, and interface inheritance yields int.MaxValue / 2; it could be any value big enough to account for deep inheritance, or I could take into account the inheritance level in which it is being implemented – not what I’m doing. Whenever we receive int.MaxValue, we know for sure that the types are not related between themselves.

Using it, we get the following results:

var someObject = new Derived();

var target = someObject.GetType();


var d1 = target.Distance(typeof(Derived));       //0

var d2 = target.Distance(typeof(Base));          //1

var d3 = target.Distance(typeof(object));        //2

var d4 = target.Distance(typeof(IInterface));    //int.MaxValue / 2

var d5 = target.Distance(typeof(string));        //int.MaxValue

var d6 = target.Distance(typeof(int));           //int.MaxValue



And if you want to find all conventions in distance order:

var conventions = new Dictionary<Type, Convention>();


var conventions = (from c in conventions

                let d = Distance(c.Key, target)

                where d < int.MaxValue

                orderby d

                select c.Value);

Have you found yourselves in this situation? What do you think of this solution? Let me hear your thoughts!

 

 

Composition in Postal.NET

Today I pushed a new feature of Postal.NET: composition. What is this? Well, think of it as (very) lightweight sagas; a subscription is only fired when a number of messages, with certain characteristics, have been received. Let’s see some examples.

First, the most basic one:

using (Postal

    .Box

    .When("channel1", "topic1")

    .And("channel2", "topic2")

    .Subscribe(env => Console.WriteLine(env.Data)))

{

    Postal.Box.Publish("channel1", "topic1", "Will not show");

    Postal.Box.Publish("channel2", "topic2", "Hello, World!");

}

Here, we wait for two messages to arrive, on two different channel/topic pairs. Only after the second does arrive do we trigger the subscriber action.

Next, a timed composition:

using (Postal

    .Box

    .When("channel1", "topic1")

    .And("channel2", "topic2")

    .InTime(TimeSpan.FromSeconds(5))

    .Subscribe(env => Console.WriteLine(env.Data)))

{

    Postal.Box.Publish("channel1", "topic1", "Will not show");

 

    Thread.Sleep(6 * 1000);

 

    Postal.Box.Publish("channel2", "topic2", "Will not show too");

}

Now we give our composition 5 seconds, from the first condition until the last one. Because we are waiting for slightly longer than that, the subscriber action will never get triggered.

Finally, a composition with conditions:

using (Postal

    .Box

    .When("channel1", "topic1", env => env.Data is int)

    .And("channel2", "topic2")

    .Subscribe(env => Console.WriteLine(env.Data)))

{

    Postal.Box.Publish("channel1", "topic1", 1);

    Postal.Box.Publish("channel2", "topic2", "Hello, World!");

}

On each of the steps, here represented by When and And, we can supply conditions, over an Envelope. If any of these conditions is not met, then the composition fails. Of course, we can add any number of conditions.

The Subscribe method must be called when we have all the conditions in place, and, as usual, it returns an IDisposable. When we want to cancel this subscription, we just dispose of it.

You can find the code in GitHub, under the PostalWhen.NET project. I will publish a Nuget package to go along with Postal.NET soon.

Hope you find this cool, as I did! Winking smile

Changes to Postal.NET

I made a few changes to my Postal.NET library: it is now released under the LGPL license, but that’s not the most important.

As of now, subscriptions do not prevent a subscriber from being garbage collected: I am using GCHandle instead of the actual Action<Envelope> delegate. I also added a minor convention that uses a class’ namespace as the channel and its name as the topic.

The most important is… it is now available in Nuget as https://www.nuget.org/packages/Postal.NET!

Enjoy, and let me know about it! Winking smile

Entity Framework Pitfalls: Entity Refresh

After an entity is loaded by Entity Framework, it gets stored in its first level cache. After that, whenever EF executes a query that returns this entity, identified by its primary key, EF always returns the cached entry, and makes no attempt to see if the cached data (the rest of the properties) is still up to date with that returned from the query. This feature is common to other ORMs, but it may result in unexpected behavior – we cannot rely on the state of a loaded entity if the database can change by other processes..

The solution for EF pre-Core is either:

  • Remove (evict) the entity from first level cache, by marking it as detached, when we want it to be reloaded from the database:
MyEntity e = ...;

 

ctx.Entry(e).State = EntityState.Detached;

  • Explicitly ask for it to be reloaded:
MyEntity e = ...;

 

ctx.Entry(e).Reload();

In EF Core, there is no Reload method – although I did write an implementation for it –, so the only option is to detach the entity from the context.

Introducing Postal.NET

Update: Postal.NET is now available in Nuget.

Introduction

Postal.NET is a library I wrote for writing in-process decoupled applications, using the Publish/Subscribe and Domain Event patterns. Is is based loosely upon the Postal.js JavaScript library. When I say loosely, I mean, I didn’t look at the source code, but I like the ideas that it implements! Smile

Postal.NET allows us to post messages to a “bus”, identified by a channel and topic pair. A channel can have any number of topics, and a topic can be in any number of channels, these are just strings.

We can subscribe to one or more channel/topic pairs and cancel each subscription when we no longer need it.

Messages are either posted synchronously or asynchronously. Each message is delivered “as-is”, but it is wrapped in an envelope that includes a couple of properties, like, the timestamp and the origin channel and topic.

Nothing too complex, yet, I hope you find it useful!

Usage

Some usages, first, a subscription and two messages being sent, one synchronously (Publish) and the other asynchronously (PublishAsync):

using (Postal.Box.Subscribe("channel", "topic", (env) => Console.WriteLine(env.Data)))

{

    //sync

    Postal.Box.Publish("channel", "topic", "Hello, World!");


    //async

    await Postal.Box.PublishAsync("channel", "topic", "Hello, Async World!");

}


Postal.Box.Publish("channel", "topic", "Does not appear because the subscription was disposed!");

Notice the using block that wraps a Subscribe call. Subscribe returns an IDisposable, which, when disposed of, terminates the subscription, hence the third message published will not be caught by the subscription.

using (Postal.Box.Subscribe("*", "*", (env) => Console.WriteLine("Catch all!")))

{

    using (Postal.Box.Subscribe("channel", "topic", (env) => Console.WriteLine(env.Data)))

    {

        Postal.Box.Publish("channel", "topic", "Hello, World!");

    }

}

Now we have two subscriptions, one for * (any) channel and topic, and the other for a concrete one. Both subscriptions will receive the message.

using (Postal.Box.Subscribe("channel", "topic", (env) => Console.WriteLine(env.Data), (env) => env.Data is int))

{

    Postal.Box.Publish("channel", "topic", "Does not show!");

    Postal.Box.Publish("channel", "topic", 12345);

}

This time we are filtering the subscription: it will only fire if the message payload is an integer.

using (var evt = new ManualResetEvent(false))

using (Postal.Box.Subscribe("channel", "topic", (env) => {

    Console.WriteLine(env.Data);

    evt.Set();

}))

{

    Postal.Box.PublishAsync("channel", "topic", "Hello, World!");


    evt.WaitOne();

}

In this example, we wait for an event to be signaled, which only happens once an asynchronous message is handled.

using (Postal.Box.AnyChannelAndTopic().Subscribe((env) => Console.WriteLine("Catch all!")))

{

    using (Postal.Box.Channel("channel").Topic("topic").Subscribe((env) => Console.WriteLine(env.Data)))

    {

        Postal.Box.Channel("channel").Topic("topic").Publish("Hello, World!");

    }

}

This final example shows the alternative fluent interface. It offers the exact same functionality.

Code

Let’s start by the Postal class, which merely acts as an holder for an IBox:

public static class Postal

{

    public static readonly IBox Box = new Box();

}

The IBox interface, the core of Postal.NET, is defined as:

public interface IBox

{

    IDisposable Subscribe(string channel, string topic, Action<Envelope> subscriber, Func<Envelope, bool> condition = null);


    void Publish(string channel, string topic, object data);

    Task PublishAsync(string channel, string topic, object data);

}

The included implementation, Box, is as follows:

public sealed class Box : IBox

{

    class SubscriberId

    {

        private readonly Guid id;

        private readonly string channel;

        private readonly string topic;

        private readonly int hash;

        private readonly Func<Envelope, bool> condition;


        public SubscriberId(Guid id, string channel, string topic, Func<Envelope, bool> condition)

        {

            this.id = id;

            this.channel = channel;

            this.topic = topic;

            this.condition = condition;


            unchecked

            {

                this.hash = 13;

                this.hash = (this.hash * 17) ^ this.id.GetHashCode();

                this.hash = (this.hash * 17) ^ this.channel.GetHashCode();

                this.hash = (this.hash * 17) ^ this.topic.GetHashCode();

            }

        }


        private string Normalize(string str)

        {

            return str

                .Replace(".", "\\.")

                .Replace("*", ".*");

        }


        public bool Matches(string channel, string topic)

        {

            var channelRegex = new Regex(this.Normalize(this.channel));

            var topicRegex = new Regex(this.Normalize(this.topic));


            return channelRegex.IsMatch(channel) == true

                   && topicRegex.IsMatch(topic);

        }


        public override bool Equals(object obj)

        {

            var other = obj as SubscriberId;


            if (other == null)

            {

                return false;

            }


            return (other.id == this.id) && (other.channel == this.channel) && (other.topic == this.topic);

        }


        public override int GetHashCode()

        {

            return this.hash;

        }


        public bool Passes(Envelope env)

        {

            return this.condition(env);

        }

    }


    class DisposableSubscription : IDisposable

    {

        private readonly SubscriberId id;

        private readonly IDictionary<SubscriberId, Action< Envelope>> subscribers;


        public DisposableSubscription(SubscriberId id, IDictionary<SubscriberId, Action<Envelope>> subscribers)

        {

            this.id = id;

            this.subscribers = subscribers;

        }


        public void Dispose()

        {

            this.subscribers.Remove(this.id);

        }

    }


    private readonly ConcurrentDictionary<SubscriberId, Action<Envelope>> subscribers = new ConcurrentDictionary<SubscriberId, Action<Envelope>>();


    public void Publish(string channel, string topic, object data)

    {

        this.Validate(channel, topic);

        this.PublishAsync(channel, topic, data).GetAwaiter().GetResult();

    }


    public IDisposable Subscribe(string channel, string topic, Action<Envelope> subscriber, Func<Envelope, bool> condition = null)

    {

        this.Validate(channel, topic);

        this.Validate(subscriber);


        if (condition == null)

        {

            condition = (env) => true;

        }


        var id = new SubscriberId(Guid.NewGuid(), channel, topic, condition);

        this.subscribers[id] = subscriber;


        return new DisposableSubscription(id, this.subscribers);

    }


    public async Task PublishAsync(string channel, string topic, object data)

    {

        this.Validate(channel, topic);


        var env = new Envelope(channel, topic, data);


        foreach (var subscriber in this.GetSubscribers(channel, topic, env).AsParallel())

        {

            await Task.Run(() => subscriber(env));

        }

    }


    private void Validate(string channel, string topic)

    {

        if (string.IsNullOrWhiteSpace(channel) == true)

        {

            throw new ArgumentNullException("channel");

        }


        if (string.IsNullOrWhiteSpace(topic) == true)

        {

            throw new ArgumentNullException("topic");

        }

    }


    private void Validate(Action<Envelope> subscriber)

    {

        if (subscriber == null)

        {

            throw new ArgumentNullException("subscriber");

        }

    }


    private void Validate(Func<Envelope, bool> condition)

    {

        if (condition == null)

        {

            throw new ArgumentNullException("condition");

        }

    }


    private bool Matches(SubscriberId id, string channel, string topic)

    {

        return id.Matches(channel, topic);

    }


    private IEnumerable<Action<Envelope>> GetSubscribers(string channel, string topic, Envelope env)

    {

        foreach (var subscriber in this.subscribers)

        {

            if (this.Matches(subscriber.Key, channel, topic) == true)

            {

                if (subscriber.Key.Passes(env) == true)

                {

                    yield return subscriber.Value;

                }

            }

        }

    }

}

And finally, the Envelope class:

public sealed class Envelope

{

    public Envelope(string channel, string topic, object data)

    {

        this.Timestamp = DateTime.UtcNow;

        this.Channel = channel;

        this.Topic = topic;

        this.Data = data;

    }


    public DateTime Timestamp { get; private set; }

    public string Channel { get; private set; }

    public string Topic { get; private set; }

    public object Data { get; private set; }

}

The code for the fluent extensions will not be covered here, but you can find it in GitHub.

Limitations

Postal.NET will not:

  • serialize messages or send them across process boundaries;
  • apply any scheduling, messages are sent immediately;
  • apply any transformation to the messages;
  • keep sent messages internally.

But it will:

  • keep the order by which messages were sent;
  • send messages to multiple channels and topics, if the * is used;
  • send any kind of data, it really doesn’t matter.

Extensions

In the GitHub repository you will find some other projects:

  • PostalRX.NET: a Reactive Extensions (RX.NET) adapter for Postal.NET;
  • PostalConventions.NET: using conventions and a fluent interface for automatically inferring the channel and topic from the message itself.

Future Works

I have a couple of ideas, but, for now, I want to keep this simple. I will update the repository as I make progress. I’d like to hear from you on this.

Conclusion

Postal.NET will hopefully let you build more decoupled applications more easily. I hope you got the idea and you see value in it. As always, I’m always happy to hear your comments!