2
votes

I am having a bear of a time getting Ninject to work with the standard ASP.net Identity solution. The stack I am using is WebApi 2.2 and Ninject 3.2.

I am using the Generated NinjectWebCommon.cs file with a slight modification, I made the CreateKernel method public, so I could register it in the OWIN pipeline.

 private static readonly Bootstrapper Bootstrapper = new Bootstrapper();
    private static IKernel _kernel;

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start()
    {

        DynamicModuleUtility.RegisterModule(typeof (OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof (NinjectHttpModule));
        Bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        Bootstrapper.ShutDown();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    public static IKernel CreateKernel()
    {
        if (_kernel != null) return _kernel;

        _kernel = new StandardKernel();
        try
        {
            _kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            _kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
            RegisterServices(_kernel);
            return _kernel;
        }
        catch
        {
            _kernel.Dispose();
            throw;
        }

    }

In my Startup.Auth.cs file, where OWIN gets configured for ASP.net Identity, I am trying to use the following setup-

 public partial class Startup
{
    static Startup()
    {
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            RefreshTokenProvider = new RefreshTokenProvider(),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(20),
#if DEBUG
            AllowInsecureHttp = true
#endif
        };
    }

    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    public static string PublicClientId { get; private set; }

    // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {
        //allow cors
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
        //use ninject in owin
        app.UseNinjectMiddleware(NinjectWebCommon.CreateKernel);
        app.UseWebApi(GlobalConfiguration.Configuration);


        // Enable the application to use bearer tokens to authenticate users
        var opts = new OAuthBearerAuthenticationOptions
        {
            AuthenticationType = "Bearer",
            AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
            Provider = new QueryStringOAuthBearerProvider("access_token")
        };
        app.UseOAuthBearerAuthentication(opts);
        app.UseOAuthAuthorizationServer(OAuthOptions);
    }
}

The problem I am getting is whenever use the app.UseNinjectMiddleware(NinjectWebCommon.CreateKernel); the app throws a "Sequence contains no elements error" with the following stacktrace-

[InvalidOperationException: Sequence contains no elements]
   System.Linq.Enumerable.Single(IEnumerable`1 source) +315
   Ninject.Web.Mvc.NinjectMvcHttpApplicationPlugin.Start() +87
   Ninject.Web.Common.Bootstrapper.<Initialize>b__0(INinjectHttpApplicationPlugin c) +29
   Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map(IEnumerable`1 series, Action`1 action) +194
   Ninject.Web.Common.Bootstrapper.Initialize(Func`1 createKernelCallback) +205
   Ninject.Web.Common.OwinHost.<Execute>d__1.MoveNext() +257
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52
   System.Runtime.CompilerServices.TaskAwaiter.GetResult() +21
   Microsoft.Owin.Cors.<Invoke>d__0.MoveNext() +1205
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52
   System.Runtime.CompilerServices.TaskAwaiter.GetResult() +21
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<RunApp>d__5.MoveNext() +287
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52
   System.Runtime.CompilerServices.TaskAwaiter.GetResult() +21
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<DoFinalWork>d__2.MoveNext() +272
   System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +22
   Microsoft.Owin.Host.SystemWeb.Infrastructure.ErrorState.Rethrow() +33
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +150
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.EndFinalWork(IAsyncResult ar) +42
   System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +415
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

Am I doing something wrong in my setup of the ninject kernel to be used in OWIN and in the rest of my IIS hosted web application?

2
Did you ever find a solution for this?Theodor Solbjørg
I didn't, and I moved away from using Ninject over to Autofac, so for me the topic is kind of OBE. However, the solution I came to, was to not use DI in the configuration class. I used raw entity queries where possible, and new-ed up other dependencies as needed.thebringking

2 Answers

1
votes

Like you, I also spent a long time wrestling with this problem. I was not able to get the recommended configuration working, despite experimenting with all the various Ninject extension assemblies and the numerous online code snippets that suggest how they should be used. As you said, the exception only occurs when OWIN is configured to use Ninject via app.UseNinjectMiddleware().

In the end, I simply eliminated OWIN from the DI process by removing the following lines from ConfigureAuth():

    app.UseNinjectMiddleware(NinjectWebCommon.CreateKernel);
    app.UseWebApi(GlobalConfiguration.Configuration);

As described in this answer, I now use Ninject to inject all the required identity components (UserManager, RoleManager etc) into the controllers that consume them.

1
votes

I think you shouldn't use Ninject.Web.WebApi.OwinHost and Ninject.Web.WebApi.WebHost together. You can only choose one.