I have this in my Application_Start:
var crumbsCache = new MemoryCache("breadCrumbsNames");
var crumbsList = new List<CacheItem>
{
//list of new CacheItem();
};
foreach (var cacheItem in crumbsList)
{
crumbsCache.Add(cacheItem, new CacheItemPolicy());
}
Now, in my controllers i am doing this:
var cache = new MemoryCache("breadCrumbsNames");
var cacheItem = cache.GetCacheItem("nameOfCacheItem");
But then cacheItem is always null, what am I doing wrong?
I think a better option for you would be to use Ninject or some other dependency injection framework to inject your MemoryCache into the controllers as needed.
You will begin by adding Ninject and Ninject.Mvc3 (and any other related bits) to your ASP.NET MVC project. If you are working in Visual Studio, you can use NuGet to do that. It is quite painless and well-automated.
The next step will be to wrap your MemoryCache into some kind of a interface, such as:
public interface IMemoryCacheService
{
MemoryCache MemoryCache
{
get;
set;
}
}
And:
public class MemoryCacheService : IMemoryCacheService
{
public MemoryCacheService()
{
MemoryCache = new MemoryCache();
}
public MemoryCache MemoryCache
{
get;
set;
}
}
Then you define a binding within Ninject so that Ninject knows that when you need something of type IMemoryCacheService, it should give you the instance of MemoryCacheService.
I will paste my own Ninject config class here. The one that will be created in your project will be very similar and will be in a folder called App_Start (which will be created automatically if you use NuGet). The class that Ninject creates by default is called NinjectWebCommon.
public static class NinjectConfig
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static void Stop()
{
bootstrapper.ShutDown();
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>()
.ToMethod(context => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>()
.To<HttpApplicationInitializationHttpModule>();
kernel.RegisterServices();
return kernel;
}
private static void RegisterServices(this IKernel kernel)
{
kernel.Bind<IMemoryCacheService>()
.To<MemoryCacheService>()
.InSingletonScope();
// InSingletonScope() is important so Ninject knows
// to create only one copy and then reuse it every time
// it is asked for
// ignore the stuff below... I have left it in here for illustration
kernel.Bind<IDbTransactionFactory>()
.To<DbTransactionFactory>()
.InRequestScope();
kernel.Bind<IDbModelContext>()
.To<DbModelContext>()
.InRequestScope();
kernel.Bind<IDbModelChangeContext>()
.To<DbModelChangeContext>()
.InRequestScope();
kernel.Bind<IUserContext>()
.To<UserContext>()
.InRequestScope();
kernel.BindAttributeAndFilter<IgnoreNonAjaxRequestsFilter, IgnoreNonAjaxRequestsAttribute>();
kernel.BindAttributeAndFilter<ProvideApplicationInfoFilter, ProvideApplicationInfoAttribute>();
kernel.BindAttributeAndFilter<ProvideSessionInfoFilter, ProvideSessionInfoAttribute>();
kernel.BindAttributeAndFilter<UseDialogLayoutFilter, UseDialogLayoutAttribute>();
kernel.BindAttributeAndFilter<CheckResourceAccessFilter, CheckResourceAccessAttribute>();
kernel.BindAttributeAndFilter<CheckResourceStateFilter, CheckResourceStateAttribute>();
}
private static void BindAttributeAndFilter<TFilter, TAttribute>(this IKernel kernel)
{
kernel.BindFilter<TFilter>(FilterScope.Action, null)
.WhenControllerHas<TAttribute>();
kernel.BindFilter<TFilter>(FilterScope.Action, null)
.WhenActionMethodHas<TAttribute>();
}
}
Finally, your controllers will change from:
public class HomeController : Controller
{
public ActionResult Foo()
{
...
}
...
}
to:
public class HomeController : Controller
{
private IMemoryCacheService memoryCacheService;
public HomeController(IMemoryCacheService memoryCacheService)
{
this.memoryCacheService = memoryCacheService;
}
public ActionResult Foo()
{
// use this.memoryCacheService in your controller methods...
}
...
}
Say, you made another service as well called IEmailService following the above-mentioned strategy, and you wanted IEmailService to be available in HomeController as well, then:
public class HomeController : Controller
{
private IMemoryCacheService memoryCacheService;
private IEmailService emailService;
public HomeController(IMemoryCacheService memoryCacheService, IEmailService emailService)
{
this.memoryCacheService = memoryCacheService;
this.emailService = emailService;
}
public ActionResult Foo()
{
// use this.memoryCacheService in your controller methods...
// and also use this.emailService in your controller methods...
}
...
}
Ninject will change the ASP.NET MVC controller factory to automatically provide the injected arguments to the controller constructors.
I think this sort of approach is better in the long run that keeping global variables, etc.
You are creating a new instance of MemoryCache in each controller. Since it is new there is nothing in it which is why you values are always null. You need to access the same instance that you created in Application_Start. Look into using MemoryCache.Default.
Related
Say, I have the below Controller
public class UsersController : Controller
{
private IUsersRepository UsersRepository { get; }
public UsersController()
{
UsersRepository = DependencyResolver.Current.GetService(typeof(IUsersRepository)) as IUsersRepository;
}
public ActionResult Index ()
{
MyUserDefinedModel data = UsersRepository.MyRepository();
return View(data);
}
}
Now I want to mock the IUsersRepository and pass it to the controller in my test script.
Below my test code
public class UsersListTest
{
private UsersController usersController = new Mock<IUsersRepository>();
private Mock<IUsersRepository> usersRepository = new UsersController();
[TestMethod]
public void TestMethod1()
{
//usersRepository.Setup(x => x.Get()).Returns(users);
}
}
As because private IUsersRepository UsersRepository { get; } private, I'm not able to pass the mock of IUsersRepository.
What would be the good idea to write unit test and mock in such case.
The reason that you have trouble with testing is because your Controller class uses the Service Locator anti-pattern. A Service Locator is a either a global instance (the DependencyResolver.Current) or an abstraction that allows resolving dependencies at runtime. One of the many downsides of the Service Locator is the problems it causes with testing.
You should move away from the Service Locator pattern and use dependency injection instead, favorably constructor injection. Your application components should have a single public constructor and those constructors should do nothing more than storing the incoming dependencies. This will result in the following UsersController implementation:
public class UsersController : Controller
{
private IUsersRepository usersRepository;
public UsersController(IUsersRepository usersRepository)
{
this.usersRepository = usersRepository;
}
public ActionResult Index()
{
return View(this.usersRepository.MyRepository());
}
}
With this in place, unit testing became trivial:
public class UsersControllerTests
{
[TestMethod]
public void Index_Always_CallsRepository()
{
// Arrange
var repository = new Mock<IUsersRepository>();
var controller = CreateValidUsersController(repository.Instance);
// Act
var result = controller.Index();
// Assert
Assert.IsTrue(repository.IsCalled);
}
// Factory method to simplify creation of the class under test with its dependencies
private UsersController CreateValidUsersController(params object[] deps) {
return new UsersController(
deps.OfType<IUsersRepository>().SingleOrDefault() ?? Fake<IUsersRepository>()
// other dependencies here
);
}
private static T Fake<T>() => (new Mock<T>()).Instance;
}
This does however, force you to change MVC's default IControllerFactory, since out-of-the-box, MVC can only handle controllers with a default constructor. But this is trivial and looks as follows:
public sealed class CompositionRoot : DefaultControllerFactory
{
private static string connectionString =
ConfigurationManager.ConnectionStrings["app"].ConnectionString;
protected override IController GetControllerInstance(RequestContext _, Type type) {
if (type == typeof(UsersController))
return new UsersController(new UsersRepository());
// [other controllers here]
return base.GetControllerInstance(_, type);
}
}
Your new controller factory can be hooked into MVC as follows:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start() {
ControllerBuilder.Current.SetControllerFactory(new CompositionRoot());
// the usual stuff here
}
}
You can find a more complete example here.
You could add a constructor that allows you to supply a mock of IUsersRepository. Your default constructor would call this with the instance from the DependencyResolver, like this:
public class UsersController : Controller
{
private IUsersRepository UsersRepository { get; }
public UsersController(IUsersRepository usersRepository)
{
UsersRepository = usersRepository;
}
public UsersController():this(DependencyResolver.Current.GetService(typeof(IUsersRepository)) as IUsersRepository)
{
}
public ActionResult Index ()
{
MyUserDefinedModel data = UsersRepository.MyRepository();
return View(data);
}
}
Currently i have class Factory which have implemented methods to return instance of Management Service (Some class)
public static class Factory
{
//#region UserNewEditDelete
public static IUserBM UserCreation()
{
return new UserBM();
}
//#endregion
}
What would be the proper way to rewrite this class Factory using Unity Framework?
My vision ::
My Factory :
public static class Factory
{
public static void Register(IUnityContainer container)
{
container.RegisterType<IUserBM, UserBM>();
}
}
Register in Global.asax :
Factory.Register(UnityConfig.GetConfiguredContainer());
when i need to use Management Service :
UnityConfig.Container.Resolve<IUserBM>()
Is it good implementation? Thanks.
Creation of unity container :
var unityContainer = new UnityContainer();
unityContainer.RegisterType<IUserBM, UserBM>();
Usage when you need an instance :
var userBm = unityContainer.Resolve<IUserBM>();
Unity is smart enough to inject that type when needed, for instance :
public class A
{
private IUserBM userBm;
public A(IUserBM userBm)
{
this.userBm = userBm;
}
public void DoSomething()
{
this.userBm.Work();
}
}
// this will construct an instance of class A injecting required types
var a = unityContainer.Resolve<A>();
a.DoSomething();
Unity with ASP.NET MVC
After installing the nuget package Unity.Mvc, edit method RegisterTypes from UnityConfig.cs
public static void RegisterTypes(IUnityContainer container)
{
unityContainer.RegisterType<IUserBM, UserBM>();
}
Now if you need an instance of IUserBm in a controller, add a constructor argument :
public class HomeController : Controller
{
private IUserBm userBm;
public HomeController(IUserBm userBm)
{
this.userBm = userBm;
}
...
Unity will create the controller for you providing an instance of the registered type thanks to UnityDependencyResolver automatically set up when you install the package.
For more information, see ASP.NET MVC 4 Dependency Injection
Referencing this CodePlex unity article I was able to get filter attribute working with a WebAPI controller as follows:
[MyFilterAttribute]
public class TestController : ApiController
{}
However, if I want to apply my filter attribute across all actions with a GlobalConfiguration it gets stripped of the injected dependency:
public class MyFilterAttribute : ActionFilterAttribute
{
[Dependency]
public MyDependency { get; set; }
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (this.MyDependency == null) //ALWAYS NULL ON GLOBAL CONFIGURATIONS
throw new Exception();
}
}
public static class UnityWebApiActivator
{
public static void Start()
{
var resolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
GlobalConfiguration.Configuration.DependencyResolver = resolver;
GlobalConfiguration.Configuration.Filters.Add(new MyFilterAttribute());
RegisterFilterProviders();
}
private static void RegisterFilterProviders()
{
var providers =
GlobalConfiguration.Configuration.Services.GetFilterProviders().ToList();
GlobalConfiguration.Configuration.Services.Add(
typeof(System.Web.Http.Filters.IFilterProvider),
new UnityActionFilterProvider(UnityConfig.GetConfiguredContainer()));
var defaultprovider = providers.First(p => p is ActionDescriptorFilterProvider);
GlobalConfiguration.Configuration.Services.Remove(
typeof(System.Web.Http.Filters.IFilterProvider),
defaultprovider);
}
}
Is there a better place to add the Global Configuration?
The problem is occurring because you are adding a newed MyFilterAttribute to the filters collection (i.e.: GlobalConfiguration.Configuration.Filters.Add(**new MyFilterAttribute()**)) as opposed to an instance resolved through Unity. Since Unity does not participate in creation of the instance, it has no trigger for injecting the dependency. This should be addressable by simply resolving the instance through Unity. e.g.:
GlobalConfiguration.Configuration.Filters.Add((MyFilterAttribute)resolver.GetService(typeof(MyFilterAttribute()));
I'm working on a design that will allow me to mock out my database so I can test my views. I don't want to read a full book on IOC because I don't have the time right now. So, this is my home cooking.
Controller:
public ActionResult Milestone()
{
var result = SJMServiceFactory.GetService("Milestone");
return View(result);
}
Factory:
public static class SJMServiceFactory
{
public static DatabaseCollection_Result<T> GetService(string serviceName)
{
switch(serviceName)
{
case("Milestone"): return MileStoneService.GetMilestone();
case ("MilestoneMock"): return MileStoneService.GetMilestone(true);
default : return default(T);
}
}
}
MileStone
public class MileStoneService
{
public MileStoneService()
{
}
public static DatabaseCollection_Result<Milestone> GetMilestone(bool Mock)
{
if (Mock)
{
DatabaseCollection_Result<Milestone> mileStones = new DatabaseCollection_Result<Milestone>();
Milestone milestone1 = new Milestone();
milestone1.Name = "New";
Milestone milestone2 = new Milestone();
milestone2.Name = "Assessment";
mileStones.Results.Add(milestone1);
mileStones.Results.Add(milestone2);
return mileStones;
}
else
return null;
}
}
I figure I need to return an interface from my factory instead of that Generic type I tried and failed at doing. I don't know how to create an interface that works for all my models, is that the wrong direction?
Without reading a whole book (does one exist? IoC is a pretty small topic in the scheme of things):
Controller:
private readonly IMilestoneService milestoneSerivce;
public MilestoneController(IMilestoneService milestoneService)
{
this.milestoneService = milestoneService;
}
public ActionResult Milestone()
{
var result = milestoneService.GetMilestones();
return View(result);
}
IMilestoneService.cs
public interface IMilestoneService
{
DatabaseCollection_Result<Milestone> GetMilestones();
}
MilestoneService.cs
public class MilestoneService : IMilestoneService
{
public DatabaseCollection_Result<Milestone> GetMilestones()
{
return null;
}
}
MockMilestoneService.cs:
public class MockMilestoneService : IMilestoneService
{
public DatabaseCollection_Result<Milestone> GetMilestones()
{
DatabaseCollection_Result<Milestone> mileStones = new DatabaseCollection_Result<Milestone>();
Milestone milestone1 = new Milestone();
milestone1.Name = "New";
Milestone milestone2 = new Milestone();
milestone2.Name = "Assessment";
mileStones.Results.Add(milestone1);
mileStones.Results.Add(milestone2);
return mileStones;
}
}
Global.asax:
ObjectFactory.Configure(x => {
x.For<IMilestoneService>().Use<MilestoneService>();
// uncomment for test
//x.For<IMilestoneService>().Use<MockMilestoneService>();
});
This uses StructureMap, but I imagine the Ninject way to wiring up the dependencies is similar. Having never used Ninject I don't know for sure, but it looks like it might be something like:
Bind<IMilestoneService>().To<MilestoneService>();
In general though I wouldn't go about creating a whole new class to test your Views, I would use a mocking framework such as Moq to create mock objects and pass them to the View and then use Assertions about the ViewResult to determine if it worked correctly.
If you're doing interactive testing though and want to be detached from the database, this might be an ok approach.
Don't fear the learning curve. IoC is a reasonably simple concept.
Ninject was the first container I picked up, and it went smoothly. The only point I really struggled with for any amount of time was how to organize all the bindings, but even that was only an issue in large applications.
YMMV, but I'd say just diving in with Ninject or similar is better investment of time than DIY.
IoC with Ninject only takes code in a few places.
1: Bind you interfaces to implementations:
public class ServiceModule : NinjectModule
{
public override void Load() {
Bind<Common.Billing.AuthorizeNet.IBillingGatewayParametersFactory>().To<AuthorizeNetParameterFactory>();
Bind<Common.Billing.IBillingGateway>().To<Common.Billing.AuthorizeNet.BillingGateway>();
}
}
2: Use constructor arguments to pass dependencies into a class:
public class BillPayingService
{
private readonly IBillingGateway _billingGateway;
public BillPayingService(
IBillingGateway billingGateway
)
{
_billingGateway = billingGateway;
}
public void PayBills()
{
// ....
}
}
3: Initialize your container on application startup:
public static class Ioc
{
public static void Initialize()
{
var modules = new INinjectModule[] {
new ServicesModule(),
new DataModule()
new VideoProcessing.NinjectModule()
};
IKernel kernel = new Ninject.StandardKernel(modules);
}
}
My Entity class has a dependency on a Repository.
public class User
{
private readonly IUserRepository _userRepository;
public User(IUserRepository userRepository)
{
_userRepository = userRepository;
}
...
}
And I have an EntityFactory class used by the Repository to create entities.
public class UserRepository : IUserRepository
{
private readonly EntityFactory _entityFactory;
public UserRepository(EntityFactory entityFactory)
{
_entityFactory = entityFactory;
}
...
}
// EntityFactory #1 with no references or dependencies to DI frameworks or CommonServiceLocator
public class EntityFactory
{
public User InstantiateUser()
{
return new User(); // Requires IUserRepository parameter
}
}
// EntityFactory #2 with reference to Ninject
using Ninject;
public class EntityFactory
{
private readonly IKernel _kernel;
public EntityFactory(IKernel kernel)
{
_kernel = kernel;
}
public User InstantiateUser(IKernel kernel)
{
return new User(_kernel.Get<IUserRepository>());
}
}
// EntityFactory #3 with reference to CommonServiceLocator
using Microsoft.Practices.ServiceLocation;
public class EntityFactory
{
public User InstantiateUser()
{
return new User(ServiceLocator.Current.GetInstance<IUserRepository>());
}
}
Is there a way to avoid the EntityFactory having a reference to the container or using the CommonServiceLocator? (Context Agnostic)
Or am I just designing my classes wrong and the User class should not have a dependency on any Repositories?
Edit: Here is the code using the method from David:
// Ninject binding
Bind<Func<User>>().ToMethod(cxt => () => new User(cxt.Kernel.Get<IUserRepository>()));
// EntityFactory class
private readonly Func<User> _userFactory;
public EntityFactory(Func<User> userFactory)
{
_userFactory = userFactory;
}
public User InstantiateUser()
{
return userFactory.Invoke();
}
Your DI framework should provide you with a method of creating factories:
public class EntityFactory
{
public EntityFactory(Func<User> userFactory) { /* ... */ }
public User InstantiateUser()
{
return userFactory.Invoke();
}
}
When the EntityFactory is created it'll receive a proper User factory which can then be used to create properly resolved users without any reference to the IoC.
What's wrong with option 2 or 3? If you are using IoC or a service locator, you will need to have a reference to it somewhere.
I have a global reference to the IoC container and use that to resolve the interfaces all over the place. This looks a lot like the service locator, but then instead using the IoC container.
I don't believe there is a way around this.