← Go Back

How to Pass HttpContext to Ninject in ASP.NET MVC

Broken Post?Let me know

I've been working with ASP.NET MVC websites that creates a connection string based on a query string value.

I've been trying to learn how to use Ninject and decided to inject repository instances to controllers.

I ran into a problem where HttpContext object instance was not available at the time of kernel binding.

I found out a solution and I'd like to share how.

Here is a simple ASP.NET MVC controller that accepts IRepository object instance. "Index" simply returns a view with "HomeIndexViewModel", which accepts a connection string from the repository (this is a very contrived example).

public class HomeController : Controller
{
		private readonly IRepository _repository;

		public HomeController(IRepository repository)
		{
				_repository = repository;
		}

		// GET: Home
		public ActionResult Index()
		{
				return View(new HomeIndexViewModel(_repository.ConnectionString));
		}
}

Repository accepts a connection string but it's retrieved via Query String argument of "db" parameter.

public class Repository : IRepository
{
	public string ConnectionString { get; set; }

	public Repository(string connectionString)
	{
		ConnectionString = connectionString;
	}
}

I've created a simplified utility class, which returns a connection string depending on the query string parameter "db".

public class QueryArgParser
{
	public HttpContext HttpContext { get; set; }

	public QueryArgParser(HttpContext httpContext)
	{
		HttpContext = httpContext;
	}

	public string GetConnectionString()
	{
		string dbValue = HttpContext.Request.QueryString["db"];
		switch (dbValue)
		{
			case "prod":
				return @"Server=GODDESS\\SQL2014;Initial Catalog=AdventureWorks2014;Integrated Security=SSPI";
			case "stage":
				return @"Server=GODDESS\\SQL2014;Initial Catalog=AdventureWorks2014Stage;Integrated Security=SSPI";
			case "dev":
				return @"Server=GODDESS\\SQL2014;Initial Catalog=AdventureWorks2014Dev;Integrated Security=SSPI";
		}

		throw new ArgumentException("Query string doesn't contain "db" parameter");
	}
}

I've installed following Ninject Nuget Packages.

Installing "Ninject.MVC3" will add a file called "NinjectWebCommon" under "App_Start" folder.

You can now register your dependencies in a method called "RegisterServices" within "NinjectWebCommon" class.

private static void RegisterServices(IKernel kernel)
{
	const string dataAccessParameterName = "connectionString";
	Func<HttpContext, string> getConnectionString =
		context => context != null ?
                    new QueryArgParser(context).GetConnectionString() :
                    string.Empty;

	kernel.Bind<IRepository>()
		.To<Repository>()
		.WithConstructorArgument(dataAccessParameterName,
			ninjectContext => getConnectionString(HttpContext.Current));
}

Line 9~13 binds "IRepository" to "Repository", which requires a contructor argument of connection string. "getConnectionString(...)" in line 4~7 is just to make the code more readable.

What's important here is the line 12~13, which is the callback within "WithConstructorArgument" that is called during RunTime, therefore "HttpContext.Current" is not null.

Now set the web start page to "?db=prod", "?db=stage", or "?db=dev"

You will see the connection string on the web page as shown below (this is for "?db=prod")

I've found the answer via StackOverflow answered by "Ruben Bartelink". One line of code Ruben posted saved me hours of headache.

The working source code is available on GitHub.