Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ninject Topshelf Microsoft.Owin.Hosting

How can I utilize Topshelf.Ninject and incorporate OwinNinjectDependencyResolver (from Ninject.Web.WebApi.OwinHost)?

I can get it to work but I need to instantiate the Ninject kernel twice (once for Topshelf and once for my HttpConfiguration.DependencyResolver. This does not seem to be the right way to use Ninject.

Any help or example code related to this specific design would be very helpful.

like image 601
codemech Avatar asked Mar 19 '23 05:03

codemech


1 Answers

So I had this same problem and I managed to solve it.

The key to this is to:

  • Not use the [assembly: OwinStartup(...)] attribute to bootstrap OWIN.
  • Inject an IKernel using Ninject into the service class being used to configure Topshelf.
  • Use the Start(StartOptions options, Action<Owin.IAppBuilder> startup) method of the Microsoft.Owin.Hosting.WebApp class to start the self-hosted web-app.
  • Pass in the injected kernel to the OWIN bootstrap routine via the startup action.
  • Use the passed-in reference to the kernel in the call to appBuilder.UseNinjectMiddleware(() => kernel); in the OWIN startup routine, rather than appBuilder.UseNinjectMiddleware(CreateKernel);.
  • Profit.

The complete solution is as follows:

  1. Create a console application solution called BackgroundProcessor.
  2. Add packages listed in the Packages.config listing below to the solution using NuGet.
  3. Add an App.config to the solution using the listing below.
  4. Add each of the code files provided below to the solution; I have provided the full listings because of the lines of code are quite sensitive to the using statements because of heavy use of extension methods by the libraries utilized by the solution.
  5. Compile and run the project.
  6. Test the solution by hitting the URL http://localhost:9000/test on your local machine.

Packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.AspNet.WebApi" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Client" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Owin" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.WebHost" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.Owin" version="2.1.0" targetFramework="net45" />
  <package id="Microsoft.Owin.Host.HttpListener" version="2.1.0" targetFramework="net45" />
  <package id="Microsoft.Owin.Hosting" version="2.1.0" targetFramework="net45" />
  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
  <package id="Ninject" version="3.2.2.0" targetFramework="net45" />
  <package id="Ninject.Extensions.ContextPreservation" version="3.2.0.0" targetFramework="net45" />
  <package id="Ninject.Extensions.NamedScope" version="3.2.0.0" targetFramework="net45" />
  <package id="Ninject.Web.Common" version="3.2.2.0" targetFramework="net45" />
  <package id="Ninject.Web.Common.OwinHost" version="3.2.2.0" targetFramework="net45" />
  <package id="Ninject.Web.WebApi" version="3.2.0.0" targetFramework="net45" />
  <package id="Ninject.Web.WebApi.OwinHost" version="3.2.1.0" targetFramework="net45" />
  <package id="Owin" version="1.0" targetFramework="net45" />
  <package id="Topshelf" version="3.1.3" targetFramework="net45" />
  <package id="Topshelf.Ninject" version="0.3.0.0" targetFramework="net45" />
</packages>

App.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Topshelf" publicKeyToken="b800c4cfcdeea87b" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.122.0" newVersion="3.1.122.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Ninject" publicKeyToken="c7192dc5380945e7" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.2.0.0" newVersion="3.2.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ninject;
using Topshelf;
using Topshelf.Ninject;

namespace BackgroundProcessor
{
    using Modules;
    using Services;

    public class Program
    {
        public static int Main(string[] args)
        {
            var exitCode = HostFactory.Run
            (
                c =>
                {
                    c.UseNinject(new Module());

                    c.Service<Service>
                    (
                        sc =>
                        {
                            sc.ConstructUsingNinject();

                            sc.WhenStarted((service, hostControl) => service.Start(hostControl));
                            sc.WhenStopped((service, hostControl) => service.Stop(hostControl));
                        }
                    );

                    c.SetServiceName("BackgroundProcessorSvc");
                    c.SetDisplayName("Background Processor");
                    c.SetDescription("Processes things in the background");

                    c.EnablePauseAndContinue();
                    c.EnableShutdown();

                    c.StartAutomaticallyDelayed();
                    c.RunAsLocalSystem();
                }
            );

            return (int)exitCode;
        }
    }
}

Modules\Module.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject.Modules;

namespace BackgroundProcessor
{
    using Contracts;
    using Services;

    namespace Modules
    {
        public class Module : NinjectModule
        {
            public override void Load()
            {
                Bind<IService>().To<Service>();
            }
        }
    }
}

Contracts\IService.cs

using System;

namespace BackgroundProcessor
{
    namespace Contracts
    {
        public interface IService
        {
            bool Start(Topshelf.HostControl hostControl);

            bool Stop(Topshelf.HostControl hostControl);
        }
    }
}

Services\Service.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Owin.Hosting;
using Ninject;
using Topshelf;

namespace BackgroundProcessor
{
    using Configs;
    using Contracts;

    namespace Services
    {
        public class Service : IService
        {
            private readonly IKernel kernel;

            public Service(IKernel kernel)
                : base()
            {
                this.kernel = kernel;
            }

            protected IKernel Kernel
            {
                get
                {
                    return this.kernel;
                }
            }

            protected IDisposable WebAppHolder
            {
                get;
                set;
            }

            protected int Port
            {
                get
                {
                    return 9000;
                }
            }

            public bool Start(HostControl hostControl)
            {
                if (WebAppHolder == null)
                {
                    WebAppHolder = WebApp.Start(new StartOptions { Port = Port }, appBuilder =>
                    {
                        new StartupConfig().Configure(appBuilder, Kernel);
                    });
                }

                return true;
            }

            public bool Stop(HostControl hostControl)
            {
                if (WebAppHolder != null)
                {
                    WebAppHolder.Dispose();
                    WebAppHolder = null;
                }

                return true;
            }
        }
    }
}

Configs\StartupConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Http;
using Ninject;
using Ninject.Web.Common.OwinHost;
using Ninject.Web.WebApi.OwinHost;
using Owin;

namespace BackgroundProcessor
{
    namespace Configs
    {
        public class StartupConfig
        {
            public void Configure(IAppBuilder appBuilder, IKernel kernel)
            {
                var config = new HttpConfiguration();

                config.MapHttpAttributeRoutes();
                config.MapDefinedRoutes();

                appBuilder.UseNinjectMiddleware(() => kernel);
                appBuilder.UseNinjectWebApi(config);
            }
        }
    }
}

Configs\RoutesConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

namespace BackgroundProcessor
{
    namespace Configs
    {
        public static class RoutesConfig
        {
            public static void MapDefinedRoutes(this HttpConfiguration config)
            {
                config.Routes.MapHttpRoute
                (
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new
                    {
                        id = RouteParameter.Optional
                    }
                );
            }
        }
    }
}

Controllers\TestController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

namespace BackgroundProcessor
{
    namespace Controllers
    {
        [RoutePrefix("test")]
        public class TestController : ApiController
        {
            [HttpGet]
            [Route("")]
            public HttpResponseMessage Index()
            {
                return Request.CreateResponse<string>(HttpStatusCode.OK, "Hello world!");
            }
        }
    }
}
like image 111
Umar Farooq Khawaja Avatar answered Mar 26 '23 08:03

Umar Farooq Khawaja