Ninject kernel suddenly loses all bindings then starts working again - c#

I am using Ninject as dependency injection tool. I have quite big asp.net-mvc 5 project (80 bindings) which, when I step through my code creates the bindings perfectly in the kernel.The NinjectWebCommon.cs. file sporadically failed on the following line of code
(kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);)
resulting in a new kernel being created and me losing all bindings to my SQL Server database.
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);
AddBindings(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
The result is that when I execute the code, I get a NULL model error in the view. The error has corrected itself automagically but I need to know what causes it so that I can rather deal with it. I include the full NinjectWebCommon.cs file
using eMedic.Domain.Abstract;
using eMedic.Domain.Concrete;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(eMedic.WebUI.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(eMedic.WebUI.App_Start.NinjectWebCommon), "Stop")]
namespace eMedic.WebUI.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();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
AddBindings(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
private static void AddBindings(IKernel kernel)
{
// add bindings here
kernel.Bind<IAccountRepository>().To<EFAccountRepository>();
kernel.Bind<IAddressRepository>().To<EFAddressRepository>();
kernel.Bind<IAddressTypeRepository>().To<EFAddressTypeRepository>();
//other bindings as well (omitted for brevity)
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
System.Web.Mvc.DependencyResolver.SetResolver(new eMedic.WebUI.Infrastructure.NinjectDependencyResolver(kernel));
}
}
}
As well as the NinjectDependencyResolver.cs class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Ninject;
using eMedic.Domain.Abstract;
using eMedic.Domain.Concrete;
namespace eMedic.WebUI.Infrastructure
{
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernelParam)
{
kernel = kernelParam;
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
}
}
The data interface
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace eMedic.Domain.Abstract
{
public interface IAddressRepository
{
IEnumerable<address> Address { get; }
}
}
and the other data interface...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using eMedic.Domain.Abstract;
namespace eMedic.Domain.Concrete
{
public class EFAddressRepository:IAddressRepository
{
private EFDbContext context = new EFDbContext();
public IEnumerable<address> Address
{
get { return context.address; }
}
}
}
I really would appreciate assistance so that I can get to the root cause of the error.

I managed to figure out what the problem was and for reference I add the reason here:
I had an error with a foreign key (FK) value in one of the tables I was referencing in my SQL Server database. It had a NULL value and when I changed the record to give that specific FK in that specific table a value, the error was cleared.

Related

InRequestScope acting like InTransientScope

I have an ASP.NET Web Application (.NET Framework 4.8) in which I've set up NInject but any services I set up with InRequestScope are coming through as if transient scope (i.e. new instances are created for every entity that depends a dependency on it - within the same web request).
The NuGet packages I am using are as follows (latest):
Ninject v3.3.4
Ninject.Web.Common v.3.32 ("Bootstrapper for web projects")
App_Start\Ninject.Web.Common.cs is present and correct and is as follows:
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(ScormWebService.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(ScormWebService.App_Start.NinjectWebCommon), "Stop")]
namespace ScormWebService.App_Start
{
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using Ninject.Web.Common.WebHost;
using Services;
using System;
using System.Web;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static IKernel Kernel { get; private set; }
/// <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
{
RegisterServices(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<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
kernel.Bind<IDumpConfigService>().To<DumpConfigService>().InSingletonScope();
// These objects are created fresh for each request
kernel.Bind<ILogService>().To<LogService>().InRequestScope();
kernel.Bind<IDumpService>().To<DumpService>().InRequestScope();
kernel.Bind<ISaveDataRequestReader>().To<SaveDataRequestReaderXml>().InRequestScope();
kernel.Bind<ISaveDataResponseWriter>().To<SaveDataResponseWriterXml>().InRequestScope();
kernel.Bind<IHttpContextAccessor>().To<HttpContextAccessor>().InRequestScope();
Kernel = kernel;
}
}
}
The incoming request is actually an implementation of IHttpHandler (i.e. an ashx rather than aspx file). However, it is still a page request with a current request and an HttpContext.Current.
Here is how I am setting up the entities for the page request
public class SaveDataHandler : IHttpHandler, IRequiresSessionState
{
/// <summary>
/// A new handler is required for each and every incoming request
/// </summary>
public bool IsReusable => false;
public SaveDataHandler()
{
var kernel = App_Start.NinjectWebCommon.Kernel;
LogService = (ILogService)kernel.GetService(typeof(ILogService));
Reader = (ISaveDataRequestReader)kernel.GetService(typeof(ISaveDataRequestReader));
Writer = (ISaveDataResponseWriter)kernel.GetService(typeof(ISaveDataResponseWriter));
DumpService = (IDumpService)kernel.GetService(typeof(IDumpService));
}
}
So for example, three instances of ILogService are created per request during the SaveDataHandler constructor instead of one: SaveDataHandler itself requests it (see above) as does class DumpService : IDumpService and class SaveDataRequestReaderXml : ISaveDataRequestReader.
Can anyone provide insight as to why InRequestScope is acting like a transient scope? I suspect the cause is using a IHttpHandler (ashx) instead of Web Form (aspx) page but I can't see why that wouldn't work as HttpContext.Current is the same across the request and that is what NInject.Web.Common uses as a request scope identifier. I've created a WebForm.aspx page but the same issue occurs for this too so it's not specific to ashx/IHttpHandler requests:
namespace ScormWebService
{
public partial class WebForm1 : Page
{
protected void Page_Init(object sender, EventArgs e)
{
var kernel = App_Start.NinjectWebCommon.Kernel;
var LogService = (ILogService)kernel.GetService(typeof(ILogService));
var Reader = (ISaveDataRequestReader)kernel.GetService(typeof(ISaveDataRequestReader));
var Writer = (ISaveDataResponseWriter)kernel.GetService(typeof(ISaveDataResponseWriter));
var DumpService = (IDumpService)kernel.GetService(typeof(IDumpService));
// At this point, three instances of LogService have been created.
}
}
}
Edit: I've created a fresh minimal ASP.NET Web Forms project that reproduces the problem which you can download here but all the essential elements are already described in the code above.
Thanks.

Run method from another class to scroll listbox to bottom

I want to autoscroll WPF ListBox to bottom automatically. I have two classes - one is Timer.cs and another one is MainWindow.xaml.cs
Here is Timer.cs:
using System;
using System.Configuration;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Importer_WPF
{
class Timer
{
public static readonly string MinutesExecution = ConfigurationManager.AppSettings["MinutesExecution"];
static System.Threading.Timer timer;
public static void StartTimer()
{
var startTimeSpan = TimeSpan.Zero;
var periodTimeSpan = TimeSpan.FromMinutes(Convert.ToDouble(MinutesExecution));
timer = new System.Threading.Timer((e) =>
{
Task.Delay(100).ContinueWith(_ => App.Current.Dispatcher.Invoke(() => MainWindow.Names.Add(DateTime.Now.ToString())));
MainWindow.AutoScroll(); // Problem is here
}, null, startTimeSpan, periodTimeSpan);
}
public static void StopTimer()
{
timer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
}
MainWindow.xaml.cs:
using System;
using System.Collections.ObjectModel;
using System.Configuration;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
namespace Importer_WPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public static ObservableCollection<string> Names { get; set; }
public static bool IsCheckedYes { get; set; }
[Obsolete]
public MainWindow()
{
InitializeComponent();
}
public void AutoScroll()
{
int itemCount = ConsoleOutput.Items.Count - 1;
if (itemCount > -1)
ConsoleOutput.ScrollIntoView(ConsoleOutput.Items[itemCount]);
}
}
}
Debugger is giving this message:
Severity Code Description Project File Line Suppression State
Error CS0120 An object reference is required for the non-static field,
method, or property 'MainWindow.AutoScroll()'
Any hints how to edit code structure so it will not produce errors?
You need to get a reference to the instance of mainwindow class which is in memory.
((MainWindow)Application.Current.MainWindow).AutoScroll();

Ninject. Binding all interfaces to the same class in singleton scope

I want one class to be both an object, which provides information about the backend, and a class, which a backend informs when servers goes down (e.g. ZooKeeper or WCF).
The problem is when I bind the same class to two different interfaces in in singleton scope, Ninject creates either two instances or throws an error, depending on how I do it.
The following example must print the same Guid and all interfaces must be bound.
Example:
Program.cs
using System;
using Ninject;
using Ninject.Modules;
namespace ConsoleApplication1
{
static class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel();
kernel.Load(new INinjectModule[] { new Bindings() });
Console.WriteLine("First interface");
var i1 = kernel.Get<IState>();
i1.Inform();
Console.WriteLine("Second interface");
var i2 = kernel.Get<IListener>();
i2.Send();
Console.ReadKey();
}
}
}
IListener.cs
namespace ConsoleApplication1
{
public interface IListener
{
void Send();
}
}
IState.cs
namespace ConsoleApplication1
{
public interface IState
{
void Inform();
}
}
StateClass.cs
using System;
namespace ConsoleApplication1
{
public class StateClass : IState, IListener
{
private readonly String _seed;
public StateClass()
{
_seed = Guid.NewGuid().ToString();
}
public void Send()
{
Console.WriteLine(_seed);
}
public void Inform()
{
Console.WriteLine(_seed);
}
}
}
Bindings.cs - Version 1 In this example everything works, if the code is commented. The problem is I dont know in advance if a class impelments IState interface it will also IListener interface:
using Ninject.Modules;
using Ninject.Extensions.Conventions;
namespace ConsoleApplication1
{
class Bindings : NinjectModule
{
public override void Load()
{
Kernel.Bind(x => x
.FromAssemblyContaining<IState>()
.SelectAllClasses()
.InheritedFrom<IState>()
.BindAllInterfaces()
.Configure(y => y.InSingletonScope()));
//uncomment the following binding to see an exception
//problem is we dont know this in advance
//Kernel.Bind(x => x
// .FromAssemblyContaining<IListener>()
// .SelectAllClasses()
// .InheritedFrom<IListener>()
// .BindAllInterfaces()
// .Configure(y => y.InSingletonScope()));
}
}
}
Bindings.cs - Version 2 - no exception, but Application prints different Guids:
using Ninject.Modules;
using Ninject.Extensions.Conventions;
namespace ConsoleApplication1
{
class Bindings : NinjectModule
{
public override void Load()
{
Kernel.Bind<IListener>().To<StateClass>().InSingletonScope();
Kernel.Bind<IState>().To<StateClass>().InSingletonScope();
}
}
}
So I think in your module you're going to have to tell Ninject that both interfaces are using the same object. if you don't, Ninject will always assume that each interface has its own singleton.
class Bindings : NinjectModule
{
public override void Load()
{
Kernel.Bind<StateClass>().ToSelf().InSingletonScope();
Kernel.Bind<IListener>().ToMethod(ctx => ctx.Kernel.Get<StateClass>());
Kernel.Bind<IState>().ToMethod(ctx => ctx.Kernel.Get<StateClass>());
}
}

Altering multiple databases with NHibernate

I'm having trouble with the copying entities between multiple databases. I can't seem to get my head around this issue and really need some help with the implementation.
My current implementation is described here:
Http module
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using ISMSControl.Infrastructure.Sessions;
using NHibernate;
using NHibernate.Context;
namespace ISMSControl.Infrastructure.Modules
{
public class SessionModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += OpenSession;
context.EndRequest += CloseSession;
}
private void CloseSession(object sender, EventArgs e)
{
ISession session = ManagedWebSessionContext.Unbind(HttpContext.Current, SessionManager.GetCurrentSession().SessionFactory);
if (session != null)
{
if (session.Transaction != null && session.Transaction.IsActive)
session.Transaction.Rollback();
else
session.Flush();
session.Close();
}
}
private void OpenSession(object sender, EventArgs e)
{
ManagedWebSessionContext.Bind(HttpContext.Current,
SessionManager.GetCurrentSession());
}
public void Dispose()
{
}
}
}
SessionManager implemenation
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using ISMSControl.Infrastructure.Mappings;
using NHibernate;
using NHibernate.Cache;
namespace ISMSControl.Infrastructure.Sessions
{
public sealed class SessionManager
{
private const string CurrentSessionKey = "nhibernate.current_session";
private static readonly ISessionFactory sessionFactory;
static SessionManager()
{
sessionFactory = CreateSessionFactory("source");
}
private static ISessionFactory CreateSessionFactory(string connectionStringName)
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ShowSql().ConnectionString(c => c.FromConnectionStringWithKey(connectionStringName)))
.CurrentSessionContext("managed_web")
.Cache(c =>
{
c.UseQueryCache();
c.ProviderClass<HashtableCacheProvider>();
})
.Diagnostics(d =>
{
d.Enable();
d.OutputToConsole();
})
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<StandardMapping>())
.BuildSessionFactory();
}
public static ISession GetCurrentSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if (currentSession == null)
{
currentSession = sessionFactory.OpenSession();
context.Items[CurrentSessionKey] = currentSession;
}
return currentSession;
}
public static void CloseSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if (currentSession == null)
{
// No current session
return;
}
currentSession.Close();
context.Items.Remove(CurrentSessionKey);
}
public static void CloseSessionFactory(string sessionFactoryName = null)
{
if (sessionFactory != null)
{
sessionFactory.Close();
}
}
}
}
Repository
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
using System.Web;
using ISMSControl.Domain;
using ISMSControl.Domain.Contracts;
using ISMSControl.Infrastructure.Sessions;
using NHibernate;
using NHibernate.Context;
namespace ISMSControl.Infrastructure.Repositories
{
public class StandardRepository : IStandardRepository
{
public void SaveOrUpdate(Standard standard)
{
var session = SessionManager.GetCurrentSession();
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(standard);
transaction.Commit();
}
}
public IEnumerable<Standard> RetrieveList()
{
return SessionManager.GetCurrentSession().CreateCriteria<Standard>().List<Standard>();
}
public void CopyTo(string database, Standard standard)
{
//how do i implement this method, so it will copy the standard entity to the other database?
}
}
}
The problem is that i'm getting all these different kind of errors like, "The session is closed.", "The entity belows to another transaction or something". "Illegal attempt to associate a collection with two open sessions".
I really hope that someone can help me out our point me in the right direction by sharing a
Tutorial
Example
etc.
CopyTo implemenation
public void CopyTo(string sessionFactoryName, Standard standard)
{
//gets a new session for the destination database from the destination sessionfactory.
using (var destinationSession = SessionFactoryContainer.Current.Get(sessionFactoryName).OpenSession())
{
//error: no persister for...
var newStandard = new Standard();
newStandard.Code = standard.Code;
newStandard.Description = standard.Description;
newStandard.Explanation = standard.Explanation;
destinationSession.Save(newStandard);
}
}
In your "CopyTo" method, you have to create a session on the second database, deep clone the second parameter of your method and then attach the cloned object to the session you opened.

Problem creating objects, class could not be found

In my bllLanguage.cs class I am not able to create dalLanguage class's objects and vice versa. It says dalLanguage.cs/bllLanguage.cs could not be found.
Whats wrong with the code below?
bllLanguage.cs
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Collections;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Proj2;
namespace Proj2.BLL.Main.Setting
{
public class bllLanguage
{
public bllLanguage()
{
//add constructor code here
}
#region Properties
/// <summary>
/// Properties
/// </summary>
private int intLanguageID;
private string strDescription;
private string strValue;
#endregion
public int LanguageID
{
get { return intLanguageID; }
set { intLanguageID = value; }
}
public string Description
{
get { return strDescription; }
set { strDescription = value; }
}
public string Value
{
get { return strValue; }
set { strValue = value; }
}
#region getLanguage
/// <summary>
/// getLanguage
/// </summary>
/// <returns></returns>
public DataSet getLanguage()
{
dalLanguage objdalLanguage = new dalLanguage(); // ERROR HERE
DataSet dsgetLanguage = objdalLanguage.getLanguage();
return dsgetLanguage;
}
#endregion
}
}
dalLanguage.cs
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Data.SqlClient;
using System.Web;
using Microsoft.ApplicationBlocks.Data;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Proj2;
namespace Proj2.DAL.Main.Setting
{
public class dalLanguage
{
public dalLanguage()
{
//constructor code here
}
#region getLanguage
/// <summary>
/// getLanguage
/// </summary>
/// <returns></returns>
public DataSet getLanguage()
{
DataSet dsgetLanguage = new DataSet();
try
{
dsgetLanguage = SqlHelper.ExecuteDataset(Constants.ConnectionString, CommandType.StoredProcedure, "[Main].[sp_getLanguage]");
}
catch (Exception ex)
{
throw ex;
}
return dsgetLanguage;
}
#endregion
}
}
the namespaces do not match
Proj2.BLL.Main.Setting
Proj2.DAL.Main.Setting
you need to specify the fully qualified name or import the namespaces. importing Proj2 only is not enough
First thing I noticed is that you lack using statement in bllLanguage.cs. add
using Proj2.DAL.Main.Setting;
in bllLanguage.cs
First of never write
catch (Exception ex)
{
throw ex;
}
Throw ex will overwrite the stacktrace!
Write just throw if you want to re throw the exception.
Question are they in the same project and if not do they have a reference to the other project?

Categories

Resources