大規模なソリューションの一部として MVC4 Web アプリ プロジェクトがあります。テストプロジェクトもあります。やり直しの予定のない大量のコードを扱っているため、常に変更を加えることができるとは限りません。
MVC4 Web アプリには、「通常の」コントローラーと Web API コントローラーがあります。RC ではなく、RTM バージョンの Web API を使用しています。
プロジェクトに IoC を導入しようとしました。(DLL をダウンロードして直接参照するのではなく) NuGet インストール手法を使用して、以下をインストールしました。
Ninject v3.0.1.10,
Ninject.MVC3 v3.0.0.6
Ninject.Extensions.Factory v3.0.1.0
Ninject.Web.Common v 3.0.0.7
私のソリューションには、Ninject を利用する他の参照コンポーネントはありません。
次に、Brad Wilson のアドバイスと彼の Github Gist https://gist.github.com/2417226、および Filip W の同様のアドバイス ( http://www.strathweb.com/2012/05/using- ) に従います。 ninject-with-the-latest-asp-net-web-api-source/、NinjectResolver を実装し、グローバル構成に「登録」しました。
Web アプリを起動すると、既定のページが のIndex
アクションにマップされますProjectController
。これはビューをレンダリングし、Knockout を使用して、ApiController
と呼ばれるアクションへの呼び出しを介して ViewModel にデータを取り込みApiProjectController.Get()
ます。
私のNinjectWebCommon.cs
コードは次のようになります。
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Web.Http;
using System.Web.Http.Dependencies;
using Ninject.Extensions.Factory;
using Ninject.Syntax;
using OfficeWebApp.Utilities;
[assembly: WebActivator.PreApplicationStartMethod(typeof(OfficeWebApp.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(OfficeWebApp.App_Start.NinjectWebCommon), "Stop")]
namespace OfficeWebApp.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
public static class NinjectWebCommon
{
private static readonly Bootstrapper Bootstrapper = new Bootstrapper();
/// <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>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IDataManagerConnection>().To<DataManagerConnection>().WithConstructorArgument("overriddenConnectionString", string.Empty);
kernel.Bind<IDataManagerConnectionFactory>().ToFactory();
}
}
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
this.resolver = resolver;
}
public void Dispose()
{
IDisposable disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.GetAll(serviceType);
}
}
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
}
ProjectController
コードは次のとおりです。
public class ProjectController : Controller
{
private readonly IDataManagerConnectionFactory _dataManagerConnectionFactory;
public ProjectController(IDataManagerConnectionFactory dataManagerConnectionFactory)
{
_dataManagerConnectionFactory = dataManagerConnectionFactory;
}
[HttpGet]
public ActionResult Index()
{
//TODO:
ViewBag.Organisation = "Preview";
return View();
}
}
...そしてApiProjectController
:
public class ApiProjectController : ApiController
{
private readonly IDataManagerConnectionFactory _dataManagerConnectionFactory;
public ProjectsController(IDataManagerConnectionFactory dataManagerConnectionFactory)
{
_dataManagerConnectionFactory = dataManagerConnectionFactory;
}
[HttpGet]
public IEnumerable<ProjectTileModel> Get()
{
using (IDataManagerConnection connection = _dataManagerConnectionFactory.Create())
{
List<ProjectTileModel> projectViewModels = connection.DataManager.GetProjectInfos()
.ToList();
return projectViewModels;
}
}
}
アクション メソッドが完了するApiProjectController.Get()
と、Ninject は次の例外をスローします。
Error loading Ninject component ICache
No such component has been registered in the kernel's component container.
Suggestions:
1) If you have created a custom subclass for KernelBase, ensure that you have properly
implemented the AddComponents() method.
2) Ensure that you have not removed the component from the container via a call to RemoveAll().
3) Ensure you have not accidentally created more than one kernel.
コール スタックは次のようになります。
Ninject.dll!Ninject.Components.ComponentContainer.Get(System.Type component) Line 160 C#
Ninject.dll!Ninject.Components.ComponentContainer.Get<Ninject.Activation.Caching.ICache>() Line 116 + 0x46 bytes C#
Ninject.Web.Common.dll!Ninject.Web.Common.OnePerRequestHttpModule.DeactivateInstancesForCurrentHttpRequest.AnonymousMethod__1(Ninject.IKernel kernel) Line 74 + 0x27 bytes C#
Ninject.dll!Ninject.GlobalKernelRegistration.MapKernels(System.Action<Ninject.IKernel> action) Line 75 + 0xe bytes C#
Ninject.Web.Common.dll!Ninject.Web.Common.OnePerRequestHttpModule.DeactivateInstancesForCurrentHttpRequest() Line 76 C#
Ninject.Web.Common.dll!Ninject.Web.Common.OnePerRequestHttpModule.Init.AnonymousMethod__0(object o, System.EventArgs e) Line 56 + 0x9 bytes C#
ComponentContainer.cs
この例外は、ファイル内の次の Ninject コードでスローされています。
Type implementation = _mappings[component].FirstOrDefault(); // <-- see note below...
if (implementation == null)
throw new InvalidOperationException(ExceptionFormatter.NoSuchComponentRegistered(component)); // <-- exception thrown here
注: 上記の行で、_mappings
コレクションには 1 つの項目が含まれています。キーType
は探している ( ICache
) と一致しますが、Values
メンバー ( List<Type>
) は空です (0 カウント)
を使用しないOnePerRequestHttpModule
でください。.ToFactory()
バインディングで使用しているため、何かおかしなことが起こっていますか? OnePerRequestHttpModule
が呼び出されている理由はよくわかりませんDeactivateInstancesForCurrentHttpRequest()
が、Ninject は内部キャッシュを取得しようとしているようです (たぶん??)
私が間違っているのは何ですか?