how to use Ninject intercept using InterceptAttribute - c#

I have a NinjectWebCommon as follow. I am unable to get the TimingInterceptor to trigger on the method that has "Timing" attribute set. It works fine if the intercetor is defined at the class level where all method call is going to be intercepted, but I would like to have the ability to specify the method I want to intercept (opt in).
I do have the Ninject.Extensions.Interception.DynamicProxy added.
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 NinjectSettings = new NinjectSettings();
var kernel = new StandardKernel(NinjectSettings);
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
GlobalConfiguration.Configuration.DependencyResolver = new BazingaNinjectResolver(kernel);
RegisterServices(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<IMyService>().To<MyService>().InRequestScope();
}
}
my Service class define as follow
public class MyService : IMyService
{
Logger log;
public MyService()
{
log = LogManager.GetLogger(this.GetType().FullName);
}
[Timing]
public string GetString()
{
log.Info("log me!!");
return "Cool string !!!!";
}
public string GetUnInterceptString()
{
return "Not intercepted";
}
}
Interceptor and attribute define as follows
public class TimingAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return request.Context.Kernel.Get<TimingInterceptor>();
}
}
public class TimingInterceptor : SimpleInterceptor
{
readonly Stopwatch _stopwatch = new Stopwatch();
protected override void BeforeInvoke(IInvocation invocation)
{
_stopwatch.Start();
}
protected override void AfterInvoke(IInvocation invocation)
{
_stopwatch.Stop();
string message = string.Format("Execution of {0} took {1}.",
invocation.Request.Method,
_stopwatch.Elapsed);
_stopwatch.Reset();
}
}

You need it to be virtual, for ninject to intercept it:
public class MyService : IMyService
{
Logger log;
public MyService()
{
log = LogManager.GetLogger(this.GetType().FullName);
}
[Timing]
public virtual string GetString()
{
log.Info("log me!!");
return "Cool string !!!!";
}
public string GetUnInterceptString()
{
return "Not intercepted";
}
}

Related

SQLiteOpenHelper - Cannot access disposed object

I have a my SQLiteOpenHelper class, which is written as a singleton. I should note that I am not doing this in Java, I am using Xamarin.Android C# to write this.
Here's a snippet from that class:
public class DatabaseHelper : SQLiteOpenHelper
{
private static readonly string TAG = typeof(DatabaseHelper).FullName;
private static readonly string _databaseName = "istockdb";
private static readonly int _databaseVersion = 32;
private static DatabaseHelper _instance;
private Context _context;
private DatabaseHelper(Context context) : base(context, _databaseName, null, _databaseVersion)
{
_context = context;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public static DatabaseHelper Instance(Context context)
{
// *** Use the application context, which will ensure that ***
// *** the Activity's context is not accidentally leaked ***
return _instance ?? (_instance = new DatabaseHelper(context.ApplicationContext));
}
}
So I have my DatabaseHelper that is a singleton and is used like this within Activities and Services:
Service:
[Service(Name=Text.MobileBackgroundHbService, Enabled = true, Exported = true), IntentFilter(new []{Intents.SyncHeartbeats})]
public class BGHeartbeatService : BaseIntentService
{
public BGHeartbeatService()
{
this._database = DatabaseHelper.Instance(Application.Context);
}
protected override void OnHandleIntent(Intent intent)
{
if (this._database == null)
this._database = DatabaseHelper.Instance(Application.Context);
if (intent.Action.Equals(Intents.SyncHeartbeats)) SyncHeartbeatRecords();
var broadcastIntent = new Intent(Intents.MobileRefresh);
SendBroadcast(broadcastIntent);
}
}
Activity, actually a BaseActivity which all Activities inherit from:
[Activity(Label = "BaseActivity")]
public abstract class BaseActivity : AppCompatActivity
{
/// <summary>
/// Reference to the current context.
/// </summary>
protected Context _context { get; set; }
/// <summary>
/// "Tag" used for Log functionallity.
/// </summary>
protected string _tag { get; set; }
/// <summary>
/// Reference To <see cref="RemoteSyncServiceConnection"/>
/// </summary>
protected RemoteSyncServiceConnection _service_connection;
/// <summary>
/// Reference To The Current SessionState.
/// </summary>
protected SessionState _session_state;
/// <summary>
/// Reference To <see cref="SyncReceiver"/>
/// </summary>
protected SyncReceiver _sync_receiver;
/// <summary>
/// Base FloatingActionButton.
/// </summary>
protected FloatingActionButton _base_fab;
/// <summary>
/// Is the Fab Menu Shown / Hid.
/// </summary>
protected static bool _is_fab_open;
protected IConnection _printer_connection;
protected string _printer_address;
protected bool _service_required;
protected bool _receiver_required;
protected MediaPlayer _media_player;
protected DatabaseHelper _database;
/// <summary>
/// <see cref="IntentFilter"/> for the <see cref="SyncReceiver"/>
/// </summary>
protected readonly string[] _intent_filters =
{
Intents.AlarmCompleteOrders,
Intents.AlarmHeartbeats,
Intents.AlarmPkas,
Intents.AlarmTrackingScans,
Intents.MobileRefresh
};
#region Lifecycle Methods
/// <summary>
/// Application Lifecycle Method.
/// </summary>
/// <param name="savedInstanceState"></param>
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// *** Initialize Xamarin.Essentials ***
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// *** Initialize the DatabaseHelper ***
if(this._database == null)
this._database = DatabaseHelper.Instance(this.ApplicationContext);
}
}
The DatabaseHelper instance is being disposed of frequently causing either services, or activities to try and access the disposed _database object.
How is this being disposed of and why?
I thought making the _instance static within the DatabaseHelper as well as making the constructor private and forcing the use of the DatabaseHelper.Instance method would keep a single instance of the DatabaseHelper that wouldn't be disposed of between activities and services?
Am I misunderstanding this?
EDIT logcat output from try/catch blocks showing the exception being thrown. The SaveHeartbeat method exists in the base activity.:
protected void SaveHeartbeat(DateTime time, string sourceActivity, [CallerMemberName] string sourceEvent = "")
{
try
{
var heartbeat = new SmartWarehouse.Shared.Models.Heartbeat(sourceActivity,
sourceEvent,
this._session_state.CurrentSession.ROWID.ToString());
this._database.InsertHeartbeat(heartbeat);
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
}
EDIT 2 DatabaseHelper.InsertHeartbeat():
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
using (var db = this.WritableDatabase)
{
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
}
Alright so my theory is that when I access the db object in the using() statement it is disposing of the database that the DatabaseHelper object uses. Also noticed that I'm not using db.InsertOrThrow() method which I should be.. Gonna do some re-working on my DatabaseHelper class to see if that resolves the issue.
It turns out that my singleton instance of the DatbaseHelper was not being disposed of.
Actually what was happening is I was disposing of the SQLiteDatabase object that was being used by the DatbaseHelper from within the helper methods.
All I had to do to actually resolve the issue was change:
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
// This using() statement is causing the disposal
using (var db = this.WritableDatabase)
{
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
}
TO:
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
// This is no longer initialized in a using() statement
var db = this.WritableDatabase;
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
SUMMARY:
By initializing my SQLiteDatabase db object inside of using() statements inside of my helper methods I was disposing of the SQLiteDatabase that my DatabaseHelper needed.

How to use unity-container interception in asp.net-core webapi

If I try to use unity interception within a asp.net-core webapi my call-handlers are never getting called. I know it works in .net-core console applications, in non core applications and even tests in the same project that do not have the webapi stuff around (resolving services from a test container).
Here is the (relevant) code I use to setup the api:
In Program.cs:
.UseUnityServiceProvider()
In Startup.cs
public void ConfigureContainer(IUnityContainer container) {
container.AddNewExtension<Interception>();
container.RegisterType<IProjectService, ProjectService>().Configure<Interception>().SetInterceptorFor<IProjectService>(new InterfaceInterceptor());
}
public void ConfigureServices(IServiceCollection services) {
...
services.AddControllersAsServices();
...
}
I suspect it has something to do with the Unity.Microsoft.DependencyInjection.ServiceProvider set by UseUnityServiceProvider() resolving the types in a way interception is not kicking in.
So what do I need to do to get interception working as it should be? Or is this a known bug somewhere?
[Update]
#Albert: Do you mean something like this:
container.RegisterType<IProjectService, ProjectService>(new InterceptionBehavior<PolicyInjectionBehavior>()); // new Interceptor<InterfaceInterceptor>()
Even when I add the InterfaceInterceptor as second parameter it does not change anything.
Some more info on the HandlerAttribute and CallHandler I use for testing purposes:
public class DummyLoggingAttribute : HandlerAttribute {
public override ICallHandler CreateHandler(IUnityContainer container)
return new DummyLoggerCallHandler(){Order = 2};
}
}
public class DummyLoggerCallHandler : ICallHandler{
private int _order;
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) {
Console.WriteLine("log vor ");
IMethodReturn result = getNext()(input, getNext);
Console.WriteLine("log danach ");
return result;
}
public int Order {
get { return _order; }
set { _order = value; }
}
}
Applied to a method as follows.
[DummyLogging]
public virtual IList<Project> GetAllProjects() {
return _projectDao.GetAll();
}
It even does not make any differences if I add the Attribute to the interface, the implementation or both.
I another .net-core console application I can even successfully use the following extension to automatically configure each registering type for interception.
/// <summary>
/// Extension für das automatische Intercepten von Methoden
/// </summary>
public class InterceptionExtension : UnityContainerExtension {
/// <summary>
/// Entfernt die Extension
/// </summary>
public override void Remove() {
Context.Registering -= OnRegister;
Context.RegisteringInstance -= OnRegisterInstance;
}
/// <summary>
/// Initialisiert die Extension
/// </summary>
protected override void Initialize() {
Container.AddNewExtension<Interception>();
Context.Registering += OnRegister;
Context.RegisteringInstance += OnRegisterInstance;
}
/// <summary>
/// Event wenn ein Type Registriert wird
/// </summary>
private void OnRegister(object sender, RegisterEventArgs e) {
if (e.TypeFrom != null) {
Container.Configure<Interception>()
.SetInterceptorFor(e.TypeFrom, new InterfaceInterceptor());
}
}
/// <summary>
/// Event wenn eine Instance Regestriert wird
/// </summary>
private void OnRegisterInstance(object sender, RegisterInstanceEventArgs e) {
Container.Configure<Interception>()
.SetInterceptorFor(e.RegisteredType, new InterfaceInterceptor());
}
}
Which leads me to the assumption that it is not a problem with registering interception but resolving services through UnityServiceProvider.
I'm not sure that this is an answer to the question.
As I understand the original issue is that the proxy class that must intercept method calls of ProjectService is not being created.
I was able to fix it by creation a class derived from IInterceptionBehavior and a little bit different type registration.
MyInterceptionBehavior:
public class MyInterceptionBehavior : IInterceptionBehavior
{
public bool WillExecute
{
get { return true; }
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Enumerable.Empty<Type>();
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
IMethodReturn result = getNext()(input, getNext);
Console.WriteLine("Interception Called");
return result;
}
}
And in ConfigureContainer() replace your IProjectService registration with this:
container.RegisterType<IProjectService, ProjectService>(
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<MyInterceptionBehavior>());
Invoke method is called every time when every method of IProjectService is called. I hope this will give you some idea or helps to make work you interception behavior.

Error loading Ninject component ICache using Web API 2

I'm receiving the following error when executing the web api controller.
I receive this error:
Error loading Ninject component ICache\r\nNo such component has been
registered in the kernel's component container.
The controller I am calling has several Interfaces which are used by the controller.
My controller constructor:
private ISDKConfiguration iSDKConfiguration;
private ISDKLogin iSDKLogin;
private ISDKLogout iSDKLogout;
private ISDKRetrieveUserSession iSDKRetrieveUserSession;
public SDKAccountController(ISDKConfiguration sdkConfiguration, ISDKLogin sdkLogin, ISDKLogout sdkLogout, ISDKRetrieveUserSession sdkRetrieveUserSession)
{
iSDKConfiguration = sdkConfiguration;
iSDKLogin = sdkLogin;
iSDKLogout = sdkLogout;
iSDKRetrieveUserSession = sdkRetrieveUserSession;
}
My HTTP Post Method
[HttpPost]
[Route("Login")]
public SDKUserDTO Login([FromBody]SDKUserDTO sdkUserDTO)
{
iSDKConfiguration.Load();
iSDKLogin.SDKUserDTO = sdkUserDTO;
iSDKLogin.Process();
iSDKRetrieveUserSession.SDKUserDTO = sdkUserDTO;
sdkUserDTO = iSDKRetrieveUserSession.Process();
return sdkUserDTO;
}
The NinjectWebCommon.cs which was included when I downloaded the Ninject.Web.Common.WebHost nuget package.
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();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new Ninject.Web.WebApi.NinjectDependencyResolver(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">
/// The kernel.
/// </param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISDKConfiguration>().To<SDKConfiguration>();
kernel.Bind<ISDKLogin>().To<SDKLogin>();
kernel.Bind<ISDKLogout>().To<SDKLogout>();
kernel.Bind<ISDKRetrieveUserSession>().To<SDKRetrieveUserSession>();
}
}
I've edited as per several articles online to include this line of code
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new Ninject.Web.WebApi.NinjectDependencyResolver(kernel);
I'm expecting to return the following json.
{
"UserID": "dhu",
"Password": "password",
"Identifier": "LoginTestUsingPostman"
}
But it's throwing the above exception.

Preventing a class method from executing more than once at a time

I have a asp.net mvc controller that when executed calls a method in a service class to open a file and start the import of records into a database. I'd somehow like to restrict this method or class so that another instance can't be created and prevent the method from being invoked again until it is done running. I've read about the singleton pattern but I'm not sure if it can be implemented because the class is instantiated by dependency injection.
Dependency injection is handled by Autofac
Service Class:
namespace Nop.Plugin.Misc.CAImport.Services
{
public class CAImportService: ICAImportService
{
#region Fields
private IProductService _productService;
private ICategoryService _categoryService;
private IManufacturerService _manufacturerService;
#endregion
#region Constructor
public CAImportService(IProductService productService,
ICategoryService categoryService,
IManufacturerService manufacturerService)
{
this._productService = productService;
this._categoryService = categoryService;
this._manufacturerService = manufacturerService;
}
#endregion
#region Methods
/// <summary>
/// Import products from tab delimited file
/// </summary>
/// <param name="fileName">String</param>
public virtual void ImportProducts(string fileName, bool deleteProducts)
{
//Do stuff to import products
}
#endregion
}
}
Controller Class:
namespace Nop.Plugin.Misc.CAImport.Controllers
{
public class MiscCAImportController: BasePluginController
{
private ICAImportService _caImportService;
public MiscCAImportController(ICAImportService caImportService)
{
this._caImportService = caImportService;
}
[AdminAuthorize]
public ActionResult ImportProducts()
{
return View("~/plugins/misc.caimport/views/misccaimport/ImportProducts.cshtml");
}
[HttpPost]
[AdminAuthorize]
public ActionResult ImportProducts(ImportProductsModel model)
{
string fileName = Server.MapPath(model.Location);
_caImportService.ImportProducts(fileName, model.DeleteProducts);
return View("~/plugins/misc.caimport/views/misccaimport/ImportProducts.cshtml", model);
}
}
}
The code below adds a lock into your service to keep other threads from executing the enclosed statements concurrently.
public class CAImportService: ICAImportService
{
// OTHER METHODS AND SECTIONS REMOVED FOR CLARITY
// Define static object for the lock
public static readonly object _lock = new object();
/// <summary>
/// Import products from tab delimited file
/// </summary>
/// <param name="fileName">String</param>
public virtual void ImportProducts(string fileName, bool deleteProducts)
{
lock (_lock)
{
//Do stuff to import products
}
}
}

How inject depedency to CompositeControl using Ninject

How to inject dependency into CompositeControl?
I tried the following approach - MyServerControl's Calculate is still null.
Thanks!
public class MyServerControl : CompositeControl
{
private TextBox TextBox1;
private TextBox TextBox2;
private Label Label1;
[Inject] // **** This is null ****
public ICalculate Calculate { get; set; }
protected override void CreateChildControls()
{
TextBox1 = new TextBox {ID = "TextBox1", Text = "1"};
Controls.Add(TextBox1);
TextBox2 = new TextBox {ID = "TextBox2", Text = "2"};
Controls.Add(TextBox2);
var button1 = new Button {ID = "Button1", Text = "Calculate"};
button1.Click += button1_Click;
Controls.Add(button1);
Label1 = new Label {ID = "Label1"};
Controls.Add(Label1);
}
private void button1_Click(object sender, EventArgs e)
{
int value1 = Int32.Parse(TextBox1.Text);
int value2 = Int32.Parse(TextBox2.Text);
Label1.Text = "Result:" + Calculate.Add(value1, value2);
}
}
public interface ICalculate
{
int Add(int x, int y);
}
public class Calculate : ICalculate
{
public int Add(int x, int y)
{
return x + y;
}
}
Default Ninject.Web.Common Bootstrapper from NuGet:
using System.Net.NetworkInformation;
[assembly: WebActivator.PreApplicationStartMethod(typeof(NinjectDemo.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(NinjectDemo.App_Start.NinjectWebCommon), "Stop")]
namespace NinjectDemo.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()
{
IKernel kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(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<ICalculate>().To<Calculate>().InSingletonScope();
}
}
}
Updated:
I'm not able to get instance to kernel in Page_Load. Am I missing something?
<my:MyServerControl ID="MyServerControl1" runat="server" />
public partial class Default : Page
{
[Inject]
public ICalculate _calculate { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
kernel.Inject(MyServerControl1); // kernel is not available
}
}
I think you could just use the feature that satisfies dependencies on an existing object. In this particular case, in any context your control is used, you just call
kernel.Inject( myControl );
where myControl is an existing instance of your composite control. This has to be called from the code behind, somewhere in the pipeline where the instance is already created. Page_Load would most probably be fine.
Edit: there are numerous ways to be able to resolve anywhere in your application. You could for example have a global service locator. But since you are using the Bootstrapper, you should be able to resolvd your kernel anywhere
var kernel = (IKernel)Bootstrapper.Container;
Your Default page doesn't know about NinjectWebCommon class existence. It also cannot know about the kernel variable which is a NinjectWebCommon.CreateKernel() method's member. The simplest solution is the following:
public static class NinjectWebCommon
{
...
private static IKernel kernel;
public static IKernel CreateKernel()
{
if(kernel != null)
return kernel;
kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
...
}
public partial class Default : Page
{
[Inject]
public ICalculate _calculate { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
NinjectWebCommon.CreateKernel().Inject(MyServerControl1);
}
}
The other way would be to use Ninject magic. Your application class would probably need to inherit from a class provided by Ninject. In MVC it's a NinjectHttpApplication class, which overrides the bootstrapper. Than you could probably go with Wiktor's answer.
Honestly I don't like that Ninject magic, as it sometimes doesn't work for me and than it's very hard to find out why. In my MVC application I ended up creating my own ConfrollerFactory, which injected the dependencies explicitly. It also may be a pain if you want to change your IOC container.
you need to register your Ioc config, see example:
public static void RegisterIoc(HttpConfiguration config)
{
var kernel = new StandardKernel(); // Ninject IoC
kernel.Bind<IMyService>().To<MyService>();
// Tell WebApi how to use our Ninject IoC
config.DependencyResolver = new NinjectDependencyResolver(kernel);
}
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());
}
}
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
this.resolver = resolver;
}
public void Dispose()
{
var 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);
}
}
Add this class in your App_start folder, and then write in Global.asax.cs:
// Tell WebApi to use our custom Ioc (Ninject)
IocConfig.RegisterIoc(GlobalConfiguration.Configuration);

Categories

Resources