Creating a TopShelf application

What is Topshelf?

Topshelf is basically a framework for creating a Windows service (it also supports Mono on Linux – although I’ve not tested this yet).

You might still ask “why do we need this, writing a Windows service isn’t difficult?”

Well a few years back I wrote a similar library, my reasoning was that I wanted to write an application which could be run as both a console application and/or as a Windows service – well Topshelf gives you this capability and more. Ofcourse, it’s also far simpler to debug a console application than a Window’s service.

Getting started

We can write our service in such a way as to have a dependency upon Topshelf or no dependency in which case we use Topshelf methods to redirect Topshelf methods to our code – let’s start by looking at this route (i.e. a non-dependency version of the service).

Topshelf has a perfectly good sample for getting started on their site’s Show me the code page.

I’m going to pretty much recreate it here, but do check out their page.

  • Create a console application (mine’s called MyTickerService)
  • Add a reference to Topshelf via Nuget
  • Create a new class called TickerService

TickerService looks like this

public class TickerService
{
   private readonly Timer timer;

   public TickerService()
   {
      timer = new Timer(5000) {AutoReset = true};
      timer.Elapsed += (sender, e) =>
      {
         Console.WriteLine("Tick:" + DateTime.Now.ToLongTimeString());
      };
   }
 
   public void Start()
   {
      Console.WriteLine("Service started");
      timer.Start();
   }

   public void Stop()
   {
      Console.WriteLine("Service stopped");
      timer.Stop();
   }
}

This is simple enough, we’re just going to keep writing out to the Console on each elaspe of the timer. The Start and Stop methods are there to just allow us to intercept the service start and then the top to allow us to set-up and clean-up anything on our service. The names can be anything we like at this point, as these will ultimately be called from the Topshelf framework methods when we write that code, which we shall do now…

We now need to edit the Program.cs file Main method. Here’s the code

static void Main(string[] args)
{
   HostFactory.Run(x =>
   {
      x.Service<TickerService>(s =>
      {
         s.ConstructUsing(name => new TickerService());
         s.WhenStarted(svc => svc.Start());
         s.WhenStopped(svc => svc.Stop());
      });

      x.SetServiceName("SampleService");
      x.SetDisplayName("Sample");
      x.SetDescription("Sample");
      x.RunAsLocalSystem();
   });
}

Now the Topshelf fluent interface allows us to run the service and as can be seen, when the service starts or stops we simply call any appropriate methods on the TickerService. We then go on to set the service name and the service’s display name and a description before the call to RunAsLocalSystem. We can also run as a specific user/password using RunAs, require a prompt for the same using RunAsPrompt and more (see Topshelf Configuration for more information).

If you now run this application via Visual Studio or from the command prompt, you’ll see the application output text on each elapsed tick. So we can now use our “service” as a standalone console application and debug it easily like this. Then if we want to use the application in a Windows service scenario we can simply run a command prompt as administrator and then use any/all of the following to install the service (once installed it will be visible in services.msc), start the service manually, stop it and uninstall it.

MyTickerService.exe install
MyTickerService.exe start
MyTickerService.exe stop
MyTickerService.exe uninstall

Alternate implementation

The sample code previously showed a way to take a standard C# class and using the Topshelf methods, turn it into a simple service. The class itself had no dependency on Topshelf, but we could have gone a different route and implemented the ServiceControl interface from Topshelf, giving us a TickerService which looks like this

public class TickerService : ServiceControl
{
   private readonly Timer timer;

   public TickerService()
   {
      timer = new Timer(5000) {AutoReset = true};
      timer.Elapsed += (sender, e) =>
      {
         Console.WriteLine("Tick:" + DateTime.Now.ToLongTimeString());
      };
   }

   public bool Start(HostControl hostControl)
   {
      Console.WriteLine("Service started");

      timer.Start();
      return true;
   }

   public bool Stop(HostControl hostControl)
   {
      Console.WriteLine("Service stopped");

      timer.Stop();
      return true;
   }
}

So the only changes here are that we implement the ServiceControl interface and with that implement the Start and Stop methods, meaning we no longer need to tell Topshelf which methods to run when the applications starts and stops, so our Program.cs Main method can now be reduced to

HostFactory.Run(x =>
{
   x.Service<TickerService>();

   x.SetServiceName("SampleService");
   x.SetDisplayName("Sample");
   x.SetDescription("Sample");
   x.RunAsLocalSystem();
});

As our TickerService constructor takes no arguments we can simply use the x.Service() call to create it.

Logging

By default Topshelf will log using TraceSource, but if you want to use one of the alternate, more advanced logging libraries such as NLog or log4net etc. Then thankfully Topshelf allows us to easily integrate these.

I’m going to use NLog. So from Nuget find a version of Topshelf.NLog comaptible with the version of Topshelf you’re using and add this package to your project.

Let’s add a fairly generic NLog configuration to the App.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
  </configSections>
  <nlog>
    <targets>
      <target name="console" type="Console" layout="${message}" />
      <target name="debugger" type="Debugger" layout="${message}"/>
    </targets>
    <rules>
      <logger name="*" minlevel="Debug" writeTo="console,debugger" />
    </rules>
  </nlog>
</configuration>

Now we’ll declare the following variable in the TickerService class

private readonly LogWriter logWriter;

within the TickerService constructor, assign the log writer thus

logWriter = HostLogger.Get<TickerService>();

and finally, in place of the Console.WriteLine in the TickerService we use logWriter.Debug for example, here’s the Elasped event

logWriter.Debug("Tick:" + DateTime.Now.ToLongTimeString());

Structured logging with Serilog

Having used several .NET logging frameworks over the years, including the Logging Application Block, log4net, NLog as well as having used various logging frameworks in other languages.

In most cases the output to a log file is a formatted string, but in the past I’ve wondered about creating my logs in a way that could be queried or grouped in a more effective way. Recently this has become more relevant with a work project where we’re starting to use the ELK stack (Elasticsearch, Logstash & Kibana).

So I decided to take a look at some of the structured logging frameworks out there for .NET.

Getting started

I’m using Serilog 2.0, so obviously things may differ from his post with the version you’re using.

Let’s create a very simply console project to try this out on

  • Create a Console application
  • Using NuGet add Serilog
  • Using NuGet add Serilog.Sinks.RollingFile
  • Using NuGet add Serilog.Sinks.Literate

Now, we’ll jump straight into the code for this example

static void Main(string[] args)
{
   Log.Logger = new LoggerConfiguration()
      .WriteTo.LiterateConsole()
      .WriteTo.RollingFile("logs\\sample-{Date}.txt")
      .MinimumLevel.Verbose()
      .CreateLogger();

   Log.Logger.Information("Application Started");

   for (int i = 0; i < 10; i++)
   {
      Log.Logger.Information("Iteration {I}", i);
   }

   Log.Logger.Information("Exiting Application");
}

In this example, we use Serilog’s fluent interface to create our configuration. Whilst Serilog can be configured via a configuration file it appears it’s positioned more towards code based configuration.

Using the WriteTo property we can set-up one or more output mechanisms. In this case I’m using a console (LiterateConsole outputs nice coloured logs to the console), a RollingFile is created in the application’s folder off of the logs folder.

By default, Serilog sets it’s minimum logging level to Information, I’ve effectively told it to log everything by setting it to Verbose in the above code.

If we run this and view the output and/or log file, we’ll find the following output

2016-07-07 15:34:07.864 +01:00 [Information] Application Started
2016-07-07 15:34:07.906 +01:00 [Information] Iteration 0
2016-07-07 15:34:07.908 +01:00 [Information] Iteration 1
2016-07-07 15:34:07.908 +01:00 [Information] Iteration 2
2016-07-07 15:34:07.909 +01:00 [Information] Iteration 3
2016-07-07 15:34:07.910 +01:00 [Information] Iteration 4
2016-07-07 15:34:07.911 +01:00 [Information] Iteration 5
2016-07-07 15:34:07.911 +01:00 [Information] Iteration 6
2016-07-07 15:34:07.912 +01:00 [Information] Iteration 7
2016-07-07 15:34:07.912 +01:00 [Information] Iteration 8
2016-07-07 15:34:07.913 +01:00 [Information] Iteration 9
2016-07-07 15:34:07.913 +01:00 [Information] Exiting Application

As our purpose was to get queryable output, this doesn’t really help a lot, what we really want is a more structured format of output, like XML or JSON.

Let’s replace the .WriteTo.RollingFile line with the following

.WriteTo.Sink(new
   RollingFileSink("logs\\sample-{Date}.txt",
      new JsonFormatter(renderMessage: true), 1073741824, 31))

Now our log file output looks like this

{"Timestamp":"2016-07-07T15:42:35.2095535+01:00","Level":"Information","MessageTemplate":"Application Started","RenderedMessage":"Application Started"}
{"Timestamp":"2016-07-07T15:42:35.2695595+01:00","Level":"Information","MessageTemplate":"Iteration {I}","RenderedMessage":"Iteration 0","Properties":{"I":0}}
{"Timestamp":"2016-07-07T15:42:35.2725598+01:00","Level":"Information","MessageTemplate":"Iteration {I}","RenderedMessage":"Iteration 1","Properties":{"I":1}}
{"Timestamp":"2016-07-07T15:42:35.2735599+01:00","Level":"Information","MessageTemplate":"Iteration {I}","RenderedMessage":"Iteration 2","Properties":{"I":2}}
{"Timestamp":"2016-07-07T15:42:35.2735599+01:00","Level":"Information","MessageTemplate":"Iteration {I}","RenderedMessage":"Iteration 3","Properties":{"I":3}}
{"Timestamp":"2016-07-07T15:42:35.2745600+01:00","Level":"Information","MessageTemplate":"Iteration {I}","RenderedMessage":"Iteration 4","Properties":{"I":4}}
{"Timestamp":"2016-07-07T15:42:35.2745600+01:00","Level":"Information","MessageTemplate":"Iteration {I}","RenderedMessage":"Iteration 5","Properties":{"I":5}}
{"Timestamp":"2016-07-07T15:42:35.2755601+01:00","Level":"Information","MessageTemplate":"Iteration {I}","RenderedMessage":"Iteration 6","Properties":{"I":6}}
{"Timestamp":"2016-07-07T15:42:35.2755601+01:00","Level":"Information","MessageTemplate":"Iteration {I}","RenderedMessage":"Iteration 7","Properties":{"I":7}}
{"Timestamp":"2016-07-07T15:42:35.2765602+01:00","Level":"Information","MessageTemplate":"Iteration {I}","RenderedMessage":"Iteration 8","Properties":{"I":8}}
{"Timestamp":"2016-07-07T15:42:35.2765602+01:00","Level":"Information","MessageTemplate":"Iteration {I}","RenderedMessage":"Iteration 9","Properties":{"I":9}}
{"Timestamp":"2016-07-07T15:42:35.2775603+01:00","Level":"Information","MessageTemplate":"Exiting Application","RenderedMessage":"Exiting Application"}

We now have Json output – which I’m sure was obvious by the use of the JsonFormatter. The use of renderMessage : true (the default for this is false) ensures the output includes the rendered message as well as the MessageTemplate etc. The rendered message is equivalent to what the textual output would be.

Returning to our original code (the Main method) we have the following Log.Logger.Information(“Iteration {I}”, i);. You’ll notice we are using the placeholder {} syntax. The “I” within the {} could be named anything you want. It’s basically the property name uses in the Json Properties field. Ofcourse we can just as easily change this to something a little more meaningful such as

Log.Logger.Information("Iteration {Iteration}", i);

What is important though is to not fall into the trap of using a String.Format for this as this would lose the Iteration property name.

Adding context

Often we’ll want to log with some more context, for example what class we’re logging from, especially in situations where we might have similar output messages throughout our code. In such cases we can use the ForContext method

Log.Logger.ForContext<Program>().Information("Application Started");

this will cause our log file output to include the property SourceContext which a value of the namespace.classname for example

"Properties":{"Iteration":9,"SourceContext":"SerilogTest.Program"

Note: You might prefer to store the ILogger returned by Log.Logger.ForContext() instead of having the long line of code every time.

Clean disposal/completion of logging

Depending upon the logging mechanism used within Serilog, you may need to call the following when your application shutsdown

Log.CloseAndFlush();

this is especially relevent if the logging mechanism is buffered.

That’s it – straightforward, easy to use and now we can read the Json log files into some appropriately capable application and query or group etc. our log entries.

Embedded NoSQL with LiteDB

I was looking for a simple file based object/document database and came across LiteDB. This gives similar functionality to MongoDB.

If you’re looking for good documentation on LiteDB, I would suggest going to Getting Started. I’ll undoubtedly duplicate some/much of what’s written there in this post which is mainly aimed at reminding me how to get up and running with LiteDB.

Getting started

It’s so easy to get started with LiteDB. Let’s first define an object model for some data that we might wish to store.

public class Artist
{
   public string Name { get; set; }
   public IList<string> Members { get; set; }
}

public class Album
{
   public int Id { get; set; }
   public Artist Artist { get; set; }
   public string Name { get; set; }
   public string Genre { get; set; }
}

We need an Id property or a property marked with a BsonId attribute on our POCO object. Whilst we can get away without this for some operations, updates (for one will fail) without the Id property/BsonId.

To use LiteDB, simply install the nuget package LiteDB and now here’s the bare minimum to create/open a LiteDB database file and get a reference to the collection for our CRUD operations

using (var db = new LiteDatabase("Albums.db"))
{
   var albums = db.GetCollection<Album>("albums");
   // now we can carry out CRUD operations on the data
}

Easy enough. The LiteCollection returned from GetCollection allows us to to work on our data in a very simple manner.

For example, let’s insert a new album

albums.Insert(
   new Album
   {
      Artist = new Artist
      {
         Name = "Led Zeppelin",
         Members = new List<string>
         {
            "Jimmy", "Robert", "JP", "John"
         }
      },
      Name = "Physical Graffiti",
      Genre = "Rock"
   });

How about retrieving all the data, we can use

var results = albums.FindAll();

We can also query for specific data using a predicate, for example

var r = albums.Find(a => a.Artist.Name == "Alice Cooper");

Note: in this example, the Artist.Name property has not been indexed, so performance would be improved by setting an index on the data.

To update we need to get the instance from LiteDB (or at least know the Id) and then makes the changes as follows

var zep = albums.Find(a => a.Artist.Name == "Led Zeppelin").First();
zep.Artist.Members[2] = "John Paul Jones";
albums.Update(zep);

Obviously in the above we’re assuming there’s at least one item (by calling First() as obviously there might be zero, one or multiple returns), the key is how we simply call the Update method.

Deleting all items from a database can be achieved, obviously by deleting the DB file or using

albums.Delete(Query.All());

or we can delete an individual item by calling

// use the Id property 
albums.Delete(album.Id); 

// or

// use a query type syntax
albums.Delete(x => x.Artist.Name == "Led Zeppelin"); 

// or

// using the Query syntax similar to deleting all items
albums.Delete(Query.EQ("Artist.Name", new BsonValue("Led Zeppelin")));

Obviously the Query syntax seems a little over the top for most things, but offers more query like syntax if required.

And there’s more

Okay I’m not intending to document everything in this single post but I have to just touch on transactions. It’s great to see the ability to use ACID transactions for use with LiteDB.

So to ensure we only commit when all operations are successful we simply use

var albums = db.GetCollection<Album>("albums");

db.BeginTrans();
// multiple operations against LiteDB
db.Commit();

Multiple Inserts

It seems (from the documentation etc.) that when we carry out an insert, LiteDB creates an “auto-transaction” around the insert for us (see Transactions and Concurrency. As such we should be aware that if we’re creating many inserts (for example from a list of objects) then it’s best from a performance point of view to not call insert multiple times.

Instead either using the IEnumerable overload of the Insert method or wrap all inserts within a transaction (I’m assuming this would also work – not yet tested).

This make sense, but can be easily forgotten.

Powershell ForEach-Object gotcha!

Are you serious Powershell !!!!?

Okay, now I’ve got that out of the way, I wrote a little Powershell command to delete the *.deleteme files as well as the folders they refer to that Nuget occasionally seems to leave behind when updating packages.

So I developed the script on the command line and all looked good so decided to turn it into a function to add to $profile.

The function kept failing with the error “Supply values for the following paraneters: Process[0]”.

This appears because my foreach looked like this

foreach 
{ 
   // some functionality
}

and even though we think that the curly brace is the block (as it is in C#) it appears we need to place the first curly brace on the same line as the foreach, thus

foreach { 
   // some functionality
}

Here's the script, when it was completed

[code language="csharp"]
function Delete-DeleteMeAndFolder
{
   ls "*.deleteme" | 
   foreach { 
      rm -Recurse -Force $_.Name.Replace(".deleteme", "")
      del $_.Name
   }
}

Running Powershell commands from you application

So, I’ve written some Powershell cmdlet’s and occasionally, might want to either use them or use Powershell built-in cmdlet’s in one of my applications. Let’s look at making this work.

Hosting Powershell

To host Powershell we include the System.Management.Automation reference (locally or from Nuget) and we can simply use

using(var ps = Powershell.Create())
{
   // add command(s) and invoke them
}

to create a Powershell host.

Calling built-in commands/cmdlet’s

As you can see, creating the Powershell host was easy enough, but now we want to invoke a command. We can write something like

ps.AddCommand("Get-Process");

foreach (var r in ps.Invoke())
{
   Console.WriteLine(r);
}

Invoke will return a collection of PSObjects, from each of these objects we can get member info, properties etc. but also the actual object returned from GetProcess, in this case a Process object. From this we can do the following (if required)

foreach (var r in ps.Invoke())
{
   var process = (Process) r.BaseObject;
   Console.WriteLine(process.ProcessName);
}

Passing arguments into a command

When adding a command, we don’t include arguments within the command string, i.e. ps.AddCommand(“Import-Module MyModule.dll”) is wrong. Instead we pass the arguments using the AddArgument method or we supply key/value pair arguments/parameters using AddParameter, so for example

ps.AddCommand("Import-Module")                 
  .AddArgument("HelloModule.dll");

// or

ps.AddCommand("Import-Module")                 
  .AddParameter("Name", "HelloModule.dll");

So the parameter is obviously the switch name without the hyphen/switch prefix and the second value is the value for the switch.

Importing and using our own Cmdlet’s

So here’s a simply Cmdlet in MyModule.dll

[Cmdlet(VerbsCommon.Get, "Hello")]
public class GetHello : Cmdlet
{
   protected override void ProcessRecord()
   {
      WriteObject("Hello World");
   }
}

My assumption was (incorrectly) that running something like the code below, would import my module then run the Cmdlet Get-Hello

ps.AddCommand("Import-Module")                 
  .AddArgument("HelloModule.dll");

ps.Invoke();

ps.AddCommand("Get-Hello");

foreach (var r in ps.Invoke())
{
   Console.WriteLine(r);
}

in fact ProcessRecord for our Cmdlet doesn’t appear to get called (although BeginProcessing does get called) and therefore r is not going to contain any result even though it would appear everything worked (i.e. no exceptions).

What seems to happen is that the Invoke method doesn’t (as such) clear/reset the command pipeline and instead we need to run the code Commands.Clear(), as below

ps.AddCommand("Import-Module")                 
  .AddArgument("HelloModule.dll");

ps.Invoke();
ps.Commands.Clear();
// the rest of the code

An alternative to the above, if one is simply executing multiple commands which have no reliance on new modules or a shared instance of Powershell, might be to create a Poweshell object, add a command and invoke it and then create another Powershell instance and run a command and so on.

With a Powershell 3 compatible System.Management.Automation we can use the following. AddStatement method

ps.AddCommand("Import-Module")                 
  .AddArgument("HelloModule.dll");
  .AddStatement()
  .AddCommand("Get-Hello");

foreach (var r in ps.Invoke())
{
   Console.WriteLine(r);
}

Importing modules into a runspace

To share the importing of modules among Powershell host instances, we could, instead look to create a runspace (which is basically an environment space if you like) and import the module into the runspace, doing something like this

var initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new [] { "HelloModule.dll" });

var runSpace = RunspaceFactory.CreateRunspace(initial);
runSpace.Open();

using(var ps = PowerShell.Create())
{
   ps.Runspace = runSpace;

   ps.AddCommand("Get-Hello");

   foreach (var r in ps.Invoke())
   {
      Console.WriteLine(r);
   }
}

In the above code, we import our modules into the initial session, from this we create our runspace and then we associated that with the our Powershell host(s) and reuse as required.

References

Windows PowerShell Host Quickstart

Environment variables in Powershell

This just demonstrates how, when you’re used to the standard Windows command prompt, Powershell can (at times) bite you.

So I was getting some Java code configured and noticed the ant script listed a different JAVA_HOME to the one I expected. In a standard Windows command prompt I would type

echo %JAVA_HOME%

and ofcourse, expect to see the folder location. So this is what I did in Powershell and instead I just got the result %JAVA_HOME% written out.

Powershell does things differently. In this case to output environment variables we need to use

echo $Env:JAVA_HOME

Doh!

To set an environment variable in Powershell we simply type

$env:JAVA_HOME="C:\Program Files\Java\jdk1.6.0_45"

References

See Windows PowerShell Tip of the Week

Where’s the Windows 10 mobile emulator?

So I’ve been working on some ideas on cross platform .NET development using Visual Studio 2015 and Xamarin. I have the Windows UWP application working fine on Windows 10 but wanted to see how it would look on Windows 10 phone – surprisingly I found the Windows 10 phone emulator didn’t exist as part of the Visual Studio installation (possibly I missed a check box when install or the likes) but it’s easy enough to get.

Just go to Downloads and tools for Windows 10 in the Other download options section there’s a Download the emulator link. From here we can download and install the Windows 10 mobile emulator.

Take a look as Test with the Microsoft Emulator for Windows 10 Mobile Test with the Microsoft Emulator for Windows 10 Mobile also which gives some useful information on using the emulator in different scenarios/configurations.

View/ViewModel resolver

In my first post on using Prism and Xamarin Forms Prism and Xamarin Forms I stated that you needed to follow the convention of views being located in a .Views. namespace and view models being located in a .ViewModels. namespace.

In fact this is not quite true. What happens is, if the ViewModelLocator.AutowireViewModel in the view is set to true, only then does Prism attempt to wire up a view model to a view and in fact the first thing it does is to look at whether the programmer has actually registered a view to a view model factory method. Only if this returns null (i.e. no factory has been supplied for a view) does it attempt the convention based approach.

Registering your View/ViewModel mapping

We can see how to register our view models with the following code snippet (this should be in your App.cs)

protected override void ConfigureViewModelLocator()
{
   base.ConfigureViewModelLocator();

   ViewModelLocationProvider.Register("XamarinTest.Views.MainPage", () => new MainPageViewModel());
}

As you can see in the above code, you need to ensure the full namespace and type name for the view, and yes it’s a magic string which is not great.

Convention based approach

Okay, so assuming no view/view model mapping has been registered for the view, we’ll now look at the convention based approach used in prism. So by default the convention based approach expects the views to be in a Views namespace and the view models to be in a ViewModels namespace, but this can be changed to suit your needs.

For example, some prefer to keep views and view models for a specific set of functionality together within the same folder or namespace as it saves jumping around a project look for each part of the specific functionality. Or maybe you find other was to layout your view/view model files which you prefer. You can assign your on Func to the ViewModelLocationProvider’s static method SetDefaultViewTypeToViewModelTypeResolver to achieve you own view model mapping.

Let’s take a look

// override this method in your App.cs file 
protected override void ConfigureViewModelLocator()
{
   base.ConfigureViewModelLocator();

   ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver(AlternateResolver);
}

Next let’s write a simple implementation of a resolver which looks for matching ViewModels by simply expecting them to be in the same namespace etc. as the view

// add this method to your App.cs
private static Type AlternateResolver(Type type)
{
   var viewName = type.FullName;
   if (String.IsNullOrEmpty(viewName))
      return null;

   var viewModel = viewName + "ViewModel";

   return Type.GetType(viewModel);
}

Note: I had intended to create an assembly lookup method that would search the assembly for matching types but limitation in what we get as part of the PCL and/or Xamarin appears to have scuppered that idea, so in the above code we simply append ViewModel to the view name. Obviously if you name your views with the View suffix, such as MainPageView, then this code is rather simplistic and will expect the view model to be named MainPageViewViewModel, I’ll leave it to the reader to amend the method as required.

Prism and Xamarin Forms

Here’s the steps for getting Prism and Xamarin Forms up and running together. For this I’m using Visual Studio 2015. Refer to a previous post on how to get a Xamarin Forms application up and running in Visual Studio 2015 if you need to.

Note: I’m using the Unity container hence I’ll be demonstrating the code using Prism.Unity.Forms, there is support for alternate IoC containers such as NInject, Mef and Autofac. Prism.Unity.Forms will automatically include Prism.Core and Prism.Forms.

  • Create a Cross-Platform, Blank App (Xamarin.Forms Portable)
  • Using NuGet, install Prism.Unity.Forms (at the time of writing – you’ll need to click on the Include prerelease option), I’ve installed v6.2.0-pe5
  • For each of the projects you’ve created you’ll now need to go to each References section and add the Prism.Unity.Forms package from NuGet
  • Prism has a convention based approach to loading view model’s, so let’s create the two folders, Views and ViewModels off of the Portable project – in fact it’s the namespace that matters, so the expectation is for views to be in the Views namespace and likewise the view models should be in the ViewModels namespace.
  • Now add a MainPage.xaml file to the Views folder, so in the Portable project right mouse click, select Add | New Item and then from Cross-Platform select Forms Xaml Page, I’ve named mine MainPage
  • In the MainPage.xaml file you’ll see the Label is bound to a MainText property, so let’s now create a MainPageViewModel.cs file in the ViewModels folder to act as our view model for this page (the default convention is for the view model for a view to be named after the view with the suffix ViewModel, i.e. MyView by default maps to MyViewModel).
  • To allow Prism to auto wire up view models we need to add the following to the XAML file (to the ContentPage)
    xmlns:mvvm="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
    mvvm:ViewModelLocator.AutowireViewModel="True"
    
  • Derive the view model from BindableBase and implement the following code to simply get things up and running
    public class MainPageViewModel : BindableBase
    {
       public string MainText { get; } = "Hello Prism World";
    }
    

    You’ll need to add using Prism.Mvvm; to resolve the BindableBase object.

  • Remove all the code from the App constructor as the MainPage will be supplied by Prism going forward.
  • Derive your App from PrismApplication instead of Application and implement the abstract methods as below
    public class App : PrismApplication
    {
       // add these methods
       protected override void OnInitialized()
       {
          NavigationService.NavigateAsync("MainPage");
       }
    
       protected override void RegisterTypes()
       {
          Container.RegisterTypeForNavigation<MainPage>();
       }
    }
    

    You’ll need to add using Prism.Unity; to resolve PrismApplication.

    OnInitialized will automatically navigate to the “MainPage” view, the magic string maps to the type name MainPage as I’m sure you can see. But in the RegisterTypeForNavigation we can change this string mapping if preferred.