Windsor container components not available on first controller action - asp.net-mvc

I'm using a configuration within the global.asax.cs to register the components but it looks the container hasn't been initialized yet at the first http request (HomeController > Index action) and it gives me a "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection." error.
I can't find a solution for this and is driving me mad!
Extract of my global.asax.cs:
protected void Application_Start()
{
InitializeContainer();
InitializeDatabase();
RegisterRoutes(RouteTable.Routes);
}
private void InitializeContainer()
{
_container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(_container));
// Register context manager.
_container.Register(
Component.For<IContextManager>()
.ImplementedBy<CoursesContextManager>()
.LifeStyle.Singleton
.Parameters(
Parameter.ForKey("connectionString").Eq(ConfigurationManager.ConnectionStrings["CoursesConnection"].ConnectionString)
)
);
// Register specifc repository implementations (can we do this more generic?)
_container.Register(
Component.For<ICourseRepository>()
.ImplementedBy<CourseRepository>()
.LifeStyle.Singleton
);
[...other interfaces and controllers registered...]
}
Controller where the exception is thrown at first http request:
public class HomeController : Controller
{
private ICourseRepository _courseRepository;
public HomeController(ICourseRepository courseRepository)
{
_courseRepository = courseRepository;
}
public ActionResult Index()
{
var courses = _courseRepository.Find(); //here is where it fails
return View(courses);
}
}
Repository/interfaces:
Generic interface:
public interface IRepository<T>
{
IQueryable<T> Find();
}
Generic repository:
public class MyRepository<T> : IRepository<T> where T : class
{
private IContextManager _contextManager;
private string _qualifiedEntitySetName;
private string _keyName;
protected ObjectContext CurrentObjectContext
{
get { return _contextManager.GetContext(); }
}
protected ObjectSet<T> ObjectSet
{
get { return CurrentObjectContext.CreateObjectSet<T>(); }
}
public MyRepository(IContextManager contextManager)
{
this._contextManager = contextManager;
this._qualifiedEntitySetName = string.Format("{0}.{1}"
, this.ObjectSet.EntitySet.EntityContainer.Name
, this.ObjectSet.EntitySet.Name);
this._keyName = this.ObjectSet.EntitySet.ElementType.KeyMembers.Single().Name;
}
public IQueryable<T> Find()
{
return ObjectSet;
}
}
Interface course based on generic repository:
public interface ICourseRepository : IRepository<Course>
{
}

if you use Unit Of Work pattern you will solve your problem
Check this post Unit Of Work Pattern, is very usefull

I found a way to handle with this at least momentarily. Because the problem happens on the first request, I've just added another action in my controller and redirect the index action to it. Probably not the best solution but can't spend more time on this issue!
public class HomeController : Controller
{
private ICourseRepository _courseRepository;
public HomeController(ICourseRepository courseRepository)
{
_courseRepository = courseRepository;
}
public ActionResult Index() // Default action in the controller, first hit
{
return RedirectToAction("Home");
}
public ActionResult Home() //The repository is available here, no exception thrown
{
var courses = _courseRepository.Find(); //here is where it fails
return View(courses);
}
}

Related

How to new up an object independent of the container? [duplicate]

I'm trying to implement IoC in my windows form application. My choice fell on Simple Injector, because it's fast and lightweight. I also implement unit of work and repository pattern in my apps. Here is the structure:
DbContext:
public class MemberContext : DbContext
{
public MemberContext()
: base("Name=MemberContext")
{ }
public DbSet<Member> Members { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();\
}
}
Model:
public class Member
{
public int MemberID { get; set; }
public string Name { get; set; }
}
GenericRepository:
public abstract class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class
{
internal DbContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(DbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
}
MemberRepository:
public class MemberRepository : GenericRepository<Member>, IMemberRepository
{
public MemberRepository(DbContext context)
: base(context)
{ }
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
public DbContext context;
public UnitOfWork(DbContext context)
{
this.context = context;
}
public void SaveChanges()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
MemberService:
public class MemberService : IMemberService
{
private readonly IUnitOfWork unitOfWork;
private readonly IMemberRepository memberRepository;
public MemberService(IUnitOfWork unitOfWork, IMemberRepository memberRepository)
{
this.unitOfWork = unitOfWork;
this.memberRepository = memberRepository;
}
public void Save(Member member)
{
Save(new List<Member> { member });
}
public void Save(List<Member> members)
{
members.ForEach(m =>
{
if (m.MemberID == default(int))
{
memberRepository.Insert(m);
}
});
unitOfWork.SaveChanges();
}
}
In Member Form I only add a textbox to input member name and a button to save to database. This is the code in member form:
frmMember:
public partial class frmMember : Form
{
private readonly IMemberService memberService;
public frmMember(IMemberService memberService)
{
InitializeComponent();
this.memberService = memberService;
}
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
memberService.Save(member);
}
}
I implement the SimpleInjector (refer to http://simpleinjector.readthedocs.org/en/latest/windowsformsintegration.html) in Program.cs as seen in the code below:
static class Program
{
private static Container container;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(new frmMember((MemberService)container.GetInstance(typeof(IMemberService))));
}
private static void Bootstrap()
{
container = new Container();
container.RegisterSingle<IMemberRepository, MemberRepository>();
container.Register<IMemberService, MemberService>();
container.Register<DbContext, MemberContext>();
container.Register<IUnitOfWork, UnitOfWork>();
container.Verify();
}
}
When I run the program and add a member, it doesn't save to database. If I changed container.Register to container.RegisterSingle, it will save to database. From the documentation, RegisterSingle will make my class to be a Singleton. I can't using RegisterLifeTimeScope because it will generate an error
"The registered delegate for type IMemberService threw an exception. The IUnitOfWork is registered as 'Lifetime Scope' lifestyle, but the instance is requested outside the context of a Lifetime Scope"
1) How to use SimpleInjector in Windows Form with UnitOfWork & Repository pattern?
2) Do I implement the patterns correctly?
The problem you have is the difference in lifestyles between your service, repository, unitofwork and dbcontext.
Because the MemberRepository has a Singleton lifestyle, Simple Injector will create one instance which will be reused for the duration of the application, which could be days, even weeks or months with a WinForms application. The direct consequence from registering the MemberRepository as Singleton is that all dependencies of this class will become Singletons as well, no matter what lifestyle is used in the registration. This is a common problem called Captive Dependency.
As a side note: The diagnostic services of Simple Injector are able to spot this configuration mistake and will show/throw a Potential Lifestyle Mismatch warning.
So the MemberRepository is Singleton and has one and the same DbContext throughout the application lifetime. But the UnitOfWork, which has a dependency also on DbContext will receive a different instance of the DbContext, because the registration for DbContext is Transient. This context will, in your example, never save the newly created Member because this DbContext does not have any newly created Member, the member is created in a different DbContext.
When you change the registration of DbContext to RegisterSingleton it will start working, because now every service, class or whatever depending on DbContext will get the same instance.
But this is certainly not the solution because having one DbContext for the lifetime of the application will get you into trouble, as you probably already know. This is explained in great detail in this post.
The solution you need is using a Scoped instance of the DbContext, which you already tried. You are missing some information on how to use the lifetime scope feature of Simple Injector (and most of the other containers out there). When using a Scoped lifestyle there must be an active scope as the exception message clearly states. Starting a lifetime scope is pretty simple:
using (ThreadScopedLifestyle.BeginScope(container))
{
// all instances resolved within this scope
// with a ThreadScopedLifestyleLifestyle
// will be the same instance
}
You can read in detail here.
Changing the registrations to:
var container = new Container();
container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
container.Register<IMemberRepository, MemberRepository>(Lifestyle.Scoped);
container.Register<IMemberService, MemberService>(Lifestyle.Scoped);
container.Register<DbContext, MemberContext>(Lifestyle.Scoped);
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);
and changing the code from btnSaveClick() to:
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
using (ThreadScopedLifestyle.BeginScope(container))
{
var memberService = container.GetInstance<IMemberService>();
memberService.Save(member);
}
}
is basically what you need.
But we have now introduced a new problem. We are now using the Service Locator anti pattern to get a Scoped instance of the IMemberService implementation. Therefore we need some infrastructural object which will handle this for us as a Cross-Cutting Concern in the application. A Decorator is a perfect way to implement this. See also here. This will look like:
public class ThreadScopedMemberServiceDecorator : IMemberService
{
private readonly Func<IMemberService> decorateeFactory;
private readonly Container container;
public ThreadScopedMemberServiceDecorator(Func<IMemberService> decorateeFactory,
Container container)
{
this.decorateeFactory = decorateeFactory;
this.container = container;
}
public void Save(List<Member> members)
{
using (ThreadScopedLifestyle.BeginScope(container))
{
IMemberService service = this.decorateeFactory.Invoke();
service.Save(members);
}
}
}
You now register this as a (Singleton) Decorator in the Simple Injector Container like this:
container.RegisterDecorator(
typeof(IMemberService),
typeof(ThreadScopedMemberServiceDecorator),
Lifestyle.Singleton);
The container will provide a class which depends on IMemberService with this ThreadScopedMemberServiceDecorator. In this the container will inject a Func<IMemberService> which, when invoked, will return an instance from the container using the configured lifestyle.
Adding this Decorator (and its registration) and changing the lifestyles will fix the issue from your example.
I expect however that your application will in the end have an IMemberService, IUserService, ICustomerService, etc... So you need a decorator for each and every IXXXService, not very DRY if you ask me. If all services will implement Save(List<T> items) you could consider creating an open generic interface:
public interface IService<T>
{
void Save(List<T> items);
}
public class MemberService : IService<Member>
{
// same code as before
}
You register all implementations in one line using Batch-Registration:
container.Register(typeof(IService<>),
new[] { Assembly.GetExecutingAssembly() },
Lifestyle.Scoped);
And you can wrap all these instances into a single open generic implementation of the above mentioned ThreadScopedServiceDecorator.
It would IMO even be better to use the command / handler pattern (you should really read the link!) for this type of work. In very short: In this pattern every use case is translated to a message object (a command) which is handled by a single command handler, which can be decorated by e.g. a SaveChangesCommandHandlerDecorator and a ThreadScopedCommandHandlerDecorator and LoggingDecorator and so on.
Your example would then look like:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
public class CreateMemberCommand
{
public string MemberName { get; set; }
}
With the following handlers:
public class CreateMemberCommandHandler : ICommandHandler<CreateMemberCommand>
{
//notice that the need for MemberRepository is zero IMO
private readonly IGenericRepository<Member> memberRepository;
public CreateMemberCommandHandler(IGenericRepository<Member> memberRepository)
{
this.memberRepository = memberRepository;
}
public void Handle(CreateMemberCommand command)
{
var member = new Member { Name = command.MemberName };
this.memberRepository.Insert(member);
}
}
public class SaveChangesCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> decoratee;
private DbContext db;
public SaveChangesCommandHandlerDecorator(
ICommandHandler<TCommand> decoratee, DbContext db)
{
this.decoratee = decoratee;
this.db = db;
}
public void Handle(TCommand command)
{
this.decoratee.Handle(command);
this.db.SaveChanges();
}
}
And the form can now depend on ICommandHandler<T>:
public partial class frmMember : Form
{
private readonly ICommandHandler<CreateMemberCommand> commandHandler;
public frmMember(ICommandHandler<CreateMemberCommand> commandHandler)
{
InitializeComponent();
this.commandHandler = commandHandler;
}
private void btnSave_Click(object sender, EventArgs e)
{
this.commandHandler.Handle(
new CreateMemberCommand { MemberName = txtName.Text });
}
}
This can all be registered as follows:
container.Register(typeof(IGenericRepository<>),
typeof(GenericRepository<>));
container.Register(typeof(ICommandHandler<>),
new[] { Assembly.GetExecutingAssembly() });
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(SaveChangesCommandHandlerDecorator<>));
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(ThreadScopedCommandHandlerDecorator<>),
Lifestyle.Singleton);
This design will remove the need for UnitOfWork and a (specific) service completely.

MVC Get/Impersonate Windows User In Repository

I have an intranet application that uses the Windows username and passes that to a procedure to return data.
I'm using dependency injection, but I don't believe I have the method to get the username separated properly.
I'm trying to keep this secure by not passing in the username as a parameter, but I also want to be able to impersonate (or bypass my GetWindowsUser() method) and send in another username so I can test results for other users.
One idea I had for this was to set a session variable in another page with another (impersonated) username, then check if that session variable exists first before grabbing the actual user name, but I couldn't figure out how to access the session variable in the repository.
WEB API CONTROLLER
public class DropDownDataController : ApiController
{
private IDropDownDataRepository _dropDownDataRepository;
//Dependency Injection using Unity.WebAPI NuGet Package
public DropDownDataController(IDropDownDataRepository dropDownDataRepository)
{
_dropDownDataRepository = dropDownDataRepository;
}
[HttpGet]
public HttpResponseMessage MyList()
{
try
{
return _dropDownDataRepository.MyList();
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
}
REPOSITORY
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
private DatabaseEntities db = new DatabaseEntities();
public HttpResponseMessage MyList()
{
//(This should be separated somehow, right?)
//Create a new instance of the Utility class
Utility utility = new Utility();
//Grab the windowsUser from the method
var windowsUser = utility.GetWindowsUser();
//Pass windowsUser parameter to the procedure
var sourceQuery = (from p in db.myProcedure(windowsUser)
select p).ToList();
string result = JsonConvert.SerializeObject(sourceQuery);
var response = new HttpResponseMessage();
response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");
return response;
}
}
INTERFACE
public interface IDropDownDataRepository : IDisposable
{
HttpResponseMessage MyList();
}
UTILITY CLASS
public class Utility
{
public string GetWindowsUser()
{
//Get the current windows user
string windowsUser = HttpContext.Current.User.Identity.Name;
return windowsUser;
}
}
UPDATE 1
In addition to what Nikolai and Brendt posted below, the following is also needed to allow Web Api controllers work with the session state.
Accessing Session Using ASP.NET Web API
Abstract the Utility class and inject it into the repository.
Then you can stub or mock for testing.
public interface IUtility
{
string GetWindowsUser();
}
public class TestUtility : IUtility
{
public string GetWindowsUser()
{
return "TestUser";
}
}
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
private IUtility _utility;
public DropDownDataRepository(IUtility utility)
{
_utility = utility;
}
}
EDIT
Also the repository should not return an HTTPResponseMessage type it should just return a List<T> of the domain model you're accessing.
i.e.
public List<Model> MyList()
{
//Grab the windowsUser from the method
var windowsUser = _utility.GetWindowsUser();
//Pass windowsUser parameter to the procedure
var sourceQuery = (from p in db.myProcedure(windowsUser)
select p).ToList();
return sourceQuery
}
Then move the JSON portion to the controller.
One idea I had for this was to set a session variable in another page
with another (impersonated) username, then check if that session
variable exists first before grabbing the actual user name, but I
couldn't figure out how to access the session variable in the
repository.
Potentially, if you add in a dependency to session, you need to isolate it, e.g.
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
// ... other fields
private ISession session;
public DropDownDataRepository(ISession session)
{
this.session = session;
}
public HttpResponseMessage MyList()
{
var myUserName = this.session.UserName;
// ... etc
With ISession being something like:
public interface ISession
{
string UserName { get; }
}
Implemented as:
public class MySession : ISession
{
public string UserName
{
get
{
// potentially do some validation and return a sensible default if not present in session
return HttpContext.Current.Session["UserName"].ToString();
}
}
}
Of course there is the potential to decouple this MySession class from HttpContext if desired.
With regards to this:
//(This should be separated somehow, right?)
//Create a new instance of the Utility class
Utility utility = new Utility();
Yes, anytime you create a new object you are tightly coupling them together, which will give you issues, for example, if you try to unit test it in isolation.
In this instance you could extract an IUtility interface from Utility:
public class Utility : IUtility
{
string GetWindowsUser();
}
Then:
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
// ... other fields
private IUtility utility;
public DropDownDataRepository(IUtility utility)
{
this.utility = utility;
// .... etc
Then you have removed the depenedency between Utility and DropDownDataRepository, and can substitute in another type or mock with ease.
I got a lot of help from Nikolai and Brent and got most of the way there with their posted answers, but ended up figuring out the complete answer on my own. The problems I was having were related to not being able to access session variables in a WebAPI. So, I'm sure there are cleaner solutions to this, but I definitely improved what I had and came up with the following code, which works.
This answer was needed to allow access to the session variable in Web Api - Accessing Session Using ASP.NET Web API
GLOBAL.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
UnityConfig.RegisterComponents();
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
//Added to allow use of session state in Web API
protected void Application_PostAuthorizeRequest()
{
if (IsWebApiRequest())
{
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
}
//Added to allow use of session state in Web API
private bool IsWebApiRequest()
{
return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(WebApiConfig.UrlPrefixRelative);
}
protected void Session_Start(Object sender, EventArgs e)
{
//Default set the session variable to none
Session["_impersonatedUser"] = "none";
}
protected void Session_End(Object sender, EventArgs e)
{
//Reset the session variable to blank
Session["_impersonatedUser"] = "";
}
}
UNITY.config
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterType<IDropDownDataRepository, DropDownDataRepository>();
container.RegisterType<IUtilityRepository, UtilityRepository>();
container.RegisterType<ISessionRepository, SessionRepository>();
//MVC5
//Unity.MVC5 NuGet Package
DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
//WEB API
//Unity.WebApi NuGet Package
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
}
WEB API CONTROLLER
public class DropDownDataController : ApiController
{
private IDropDownDataRepository _dropDownDataRepository;
//Dependency Injection using Unity.WebAPI NuGet Package
public DropDownDataController(IDropDownDataRepository dropDownDataRepository)
{
_dropDownDataRepository = dropDownDataRepository;
}
[HttpGet]
public HttpResponseMessage MyList()
{
try
{
var sourceQuery = _dropDownDataRepository.MyList();
//JSON stuff moved to controller
string result = JsonConvert.SerializeObject(sourceQuery);
var response = new HttpResponseMessage();
response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");
return response;
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
protected override void Dispose(bool disposing)
{
_dropDownDataRepository.Dispose();
base.Dispose(disposing);
}
}
DROPDOWNDATA REPOSITORY
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
private DatabaseEntities db = new DatabaseEntities();
private IUtilityRepository _utilityRepository;
private ISessionRepository _sessionRepository;
//Dependency Injection of Utility and Session
public DropDownDataRepository(IUtilityRepository utilityRepository, ISessionRepository sessionRepository)
{
_utilityRepository = utilityRepository;
_sessionRepository = sessionRepository;
}
//Changed to a list here
public List<MyProcedure> MyList()
{
string windowsUser;
//Check the session variable to see if a user is being impersonated
string impersonatedUser = _sessionRepository.ImpersonatedUser;
//Grab the windowsUser from the Utility Repository
windowsUser = _utilityRepository.GetWindowsUser();
if (impersonatedUser != "none")
{
windowsUser = impersonatedUser;
}
//Pass windowsUser parameter to the procedure
var sourceQuery = (from p in db.MyProcedure(windowsUser)
select p).ToList();
return sourceQuery;
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
db.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
DROPDOWNDATA INTERFACE
public interface IDropDownDataRepository : IDisposable
{
//Changed to list here
List<MyProcedure> MyList();
}
UTILITY REPOSITORY
public class UtilityRepository : IUtilityRepository
{
public string GetWindowsUser()
{
//Get the current windows user
string windowsUser = HttpContext.Current.User.Identity.Name;
return windowsUser;
}
}
UTILITY INTERFACE
public interface IUtilityRepository
{
string GetWindowsUser();
}
SESSION REPOSITORY
public class SessionRepository : ISessionRepository
{
public string ImpersonatedUser
{
get
{
return HttpContext.Current.Session["_impersonatedUser"].ToString();
}
}
}
SESSION INTERFACE
public interface ISessionRepository
{
string ImpersonatedUser { get; }
}

Unity how to pass Request in Controller's constructor from Unity

The old controller code with Concrete dependencies:
public SomeController: Controller
{
public SomeController()
{
}
public ActionResult Default()
{
**Something something = new Something(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString());**
something.SomeMethod();
}
}
The new Controller code with TDD focus:
public SomeControllerNew: Controller
{
private readonly ISomething _something;
public SomeControllerNew(ISomething something)
{
_something = something;
}
public ActionResult Default()
{
_something.SomeMethod();
}
}
PROBLEM:
Now in new TDD approach i need to invoke constructor where I am registering the Interface. I have put it in UnityBootstraper common file, Something like:
var container = new UnityContainer();
container.RegisterType();
**Something something = new Something(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString());**
something.SomeMethod();
This is not working here. Error is quite clear:
Object reference required for non-static field, method, property 'System.Web.Mvc.Controller.Request.get'.
I can't figure out how i can access http request here in UnityBootstrapper?
Edit:
Trying to do all this in RegisterRoutes.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
DependencyResolver.SetResolver(new Unity.Mvc3.UnityDependencyResolver(UnityBootstrapper.Initialise()));
var container = new UnityContainer();
container.RegisterType<ISometing, Something>();
}
}
One way to do it is to create an abstract factory like this:
public interface ISomethingFactory
{
ISomething Create(string url);
}
public class SomethingFactory : ISomethingFactory
{
public ISomething Create(string url)
{
return new Something(url);
}
}
And make your controller depend on it like this:
public class SomeControllerNew: Controller
{
private readonly ISomething _something;
public SomeControllerNew(ISomethingFactory somethingFactory)
{
_something = somethingFactory.Create(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString();
}
public ActionResult Default()
{
_something.SomeMethod();
}
}
A better approach (IMO) is to use a custom Controller Factory instead of using the Dependency Resolver like this:
public class CustomFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
var request = requestContext.HttpContext.Request; //Here we have access to the request
if (controllerName == "Some") //Name of controller
{
//Use the container to resolve and return the controller.
//When you resolve, you can use ParameterOverride to specify the value of the string dependency that you need to inject into Something
}
return base.CreateController(requestContext, controllerName);
}
}
This way you don't have to introduce the ISomethingFactory, and your controller would still depend on ISomething directly.
You would need to tell the MVC framework about this custom controller factory like this (in Application_Start):
ControllerBuilder.Current.SetControllerFactory(new CustomFactory());

MVC 3 + IoC + NInject + Repositories + LINQ

I'm trying to work with NInject in my MVC 3 application, and i have one question.
Interface
public interface ITalesRepository
{
IEnumerable<Tale> GetAllTales();
}
Repository
public class TalesRepository : ITalesRepository
{
private FairyTalesMVC3DataContext _dataContext;
public TalesRepository(FairyTalesMVC3DataContext dataContext)
{
_dataContext = dataContext;
}
public IEnumerable<Tale> GetAllTales()
{
return _dataContext.Tales.OrderBy(c => c.NameAn);
}
}
Home controller
public class HomeController : Controller
{
private readonly ITalesRepository _talesRepository;
public HomeController(ITalesRepository talesRepository)
{
_talesRepository = talesRepository;
}
public ActionResult Index()
{
ViewBag.Tales = _talesRepository.GetAllTales();
return View();
}
}
So, i need to initialize my TalesRepository with DataContext, and now it is so:
private void RegisterDependencyResolver()
{
var kernel = new StandardKernel();
kernel.Bind<ITalesRepository>().To<TalesRepository>().WithConstructorArgument("dataContext", new FairyTalesMVC3DataContext(ConfigurationManager.ConnectionStrings["dbFairyTalesConnectionString"].ConnectionString));
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
So, my question, is it ok or something wrong?
First of all:
public IEnumerable<Tale> GetAllTales()
{
return _dataContext.Tales.OrderBy(c => c.NameAn);
}
I would add .ToList() to the end. Else you'll get data layer exceptions in your presentation layer which is not fine.
Next, I would recommend that you switch to ViewModels instead of using ViewBag. It's a lot easier to prevent that logic leaks into the views if you are using ViewModels. Since you can add the logic to the ViewModel and thus get the same behaviour in all views using the model.
Your application should inherit from NinjectHttpApplication. It registers dependency resolver, so you don't have to do it.
You should also override CreateKernel in application class and register your own module with bindings:
public class MvcApplication : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
return new StandardKernel(new INinjectModule[] {new MvcModule()});
}
}
public class MvcModule : NinjectModule
{
public override void Load()
{
Bind<ITalesRepository>().To<TalesRepository>();
Bind<FairyTalesMVC3DataContext>().To<FairyTalesMVC3DataContext>().InRequestScope();
}
}

Ninject And Connection Strings

I am very new to Ninject and am trying Ninject 2 with MVC and Linq. I have a SqlProductRepository class and all I want to know is what's the best way of passing the connectionstring in the constructor if I am injecting the Repository object in the controller.
public class SqlProductRepository:IProductRepository
{
private Table<Product> productsTable;
public SqlProductRepository(string connectionString)
{
productsTable = (new DataContext(connectionString)).GetTable<Product>();
}
public IQueryable<Product> Products
{
get { return productsTable; }
}
}
This is my ProductController class where I am injecting the Repository:
public class ProductsController : Controller
{
private int pageSize = 4;
public int PageSize { get { return pageSize; } set { pageSize = value; } }
IProductRepository _productsRepository;
[Inject]
public ProductsController(IProductRepository productRepository)
{
_productsRepository = productRepository;
}
public ViewResult List(int page)
{
return View(_productsRepository.Products
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToList()
);
}
}
Can somebody please guide me regarding this?
You can set it up in your binding
_kernel.Bind<IProductRepository>()
.To<SqlProductRepository>()
.WithConstructorArgument("connectionString",yourConnectionString );
You're doing:
new DataContext(connectionString)
in your code - this is the very newing and binding to classes you're trying to push out of your code by using a DI container. At the very least, consider adding an IConnectionStringSelector interface or something like that. You dont want to have 20 Bind calls for 20 repositories - you want a higher level abstraction than that.
I'd suggest the best solution is that you should be demanding either an IDataContext or an IDataContextFactory in the constructor instead and letting that worry about it.
You could supply the connection string as a constructor argument when binding the SqlProductRepository to the IProductRepository interface.
public class LinqToSqlModule : NinjectModule
{
public override void Load()
{
Bind<IProductRepository>().To<SqlProductRepository>()
.WithConstructorArgument(connectionString, "connectionstring");
}
}
I would suggest a slightly different approach. First of all, you might want to create a binding for the DataContext class in the kernel. You could do so by using a provider class to create your DataContext passing the connection string as an argument to its constructor. Then you bind the DataContext to the DataContextProvider.
public class DataContextProvider : Provider<DataContext>
{
protected override DataContext CreateInstance(IContext context)
{
string connectionString = "connectionstring";
return new DataContext(connectionString);
}
}
public class LinqToSqlModule : NinjectModule
{
public override void Load()
{
Bind<DataContext>().ToProvider<DataContextProvider>();
Bind<IProductRepository>().To<SqlProductRepository>();
}
}
Next modify the constructor of SqlProductRepository class to accept a DataContext object instead.
public class SqlProductRepository : IProductRepository
{
private readonly DataContext context;
public ProductRepository(DataContext context)
{
this.context = context;
}
public IQueryable<Product> Products
{
get { return context.GetTable<Product>(); }
}
}
By the way you don't have to decorate your constructor with the Inject attribute. Ninject will select the constructor with the most parameters by default.
Please refer below code snap:
//Bind the default connection string
public void BindDataContext()
{
ConstructorArgument parameter = new ConstructorArgument("connectionString", "[Config Value]");
Bind<DataContext>().ToSelf().InRequestScope().WithParameter(parameter);
}
//Re-Bind the connection string (in case of multi-tenant architecture)
public void ReBindDataContext(string cn)
{
ConstructorArgument parameter = new ConstructorArgument("connectionString", cn);
Rebind<DataContext>().ToSelf().InRequestScope().WithParameter(parameter);
}
For more information, please visit below link
MVC3, Ninject and Ninject.MVC3 problem

Resources