How can I achieve the following using IOC? - inversion-of-control

I want to use IOC with my service and I want to instead inject a class not an interface in the constructor as below in the services layer but I do not want to create a new object from the calling layer like var service = new InvoiceService(new ChangeInvoiceDueDateCommand()) instead I want to create something like this from my controller in MVC where the IInvoiceService is injected into the controller constructor but the problem I see is that
public InvoiceController(IInvoiceService invoiceService, IMapper mapper)
{
_invoiceService = invoiceService;
_mapper = mapper;
}
and then called like this
public ActionResult ChangeInvoiceDueDate(InvoiceChangeDueDateViewModel invoiceChangeDueDateViewModel )
{
var request = _mapper.Map<InvoiceChangeDueDateViewModel, ChangeInvoiceDuedateRequest>(invoiceChangeDueDateViewModel);
InvoiceChangeDueDateResponse response = _invoiceService.ChangeDueDate(request);
return View();
}
Service Layer
public class InvoiceService : IInvoiceService
{
private readonly ChangeInvoiceDueDateCommand _changeInvoiceDueDateCommand;
public InvoiceService(ChangeInvoiceDueDateCommand changeInvoiceDueDateCommand)
{
_changeInvoiceDueDateCommand = changeInvoiceDueDateCommand;
}
public InvoiceChangeDueDateResponse ChangeDueDate(ChangeInvoiceDuedateRequest invoiceChangeDueDateRequest)
{
_changeInvoiceDueDateCommand.Execute(invoiceChangeDueDateRequest);
return new InvoiceChangeDueDateResponse {Status = new Status()};
}
}
Command
public class ChangeInvoiceDueDateCommand : ICommand<ChangeInvoiceDuedateRequest>
{
private readonly IRepository<Invoice> _invoiceRepository;
readonly InvoiceDueDateChangeValidator _validator;
public ChangeInvoiceDueDateCommand(IRepository<Invoice> invoiceRepository)
{
_invoiceRepository = invoiceRepository;
_validator = new InvoiceDueDateChangeValidator();
}
public void Execute(ChangeInvoiceDuedateRequest request)
{
if (_validator.IsDuedateValid(request.NewDuedate))
{
Invoice invoice = _invoiceRepository.GetById(request.Id);
invoice.ChangedDueDate(request.NewDuedate);
_invoiceRepository.SaveOrUpdate(invoice);
}
else
{
throw new InvalidDueDateException();
}
}
}
ICommand
public interface ICommand<T> where T : IRequest
{
void Execute(T request);
}
IRequest
public interface IRequest
{
int Id { get; set; }
}

I worked it out. It was just a Windsor syntax issue. It ended up being as simple as registering the Command using the container.Register(Component.For<ChangeInvoiceDueDateCommand>());

Related

With LightInject, how can I pass arguments to child dependencies without registering a bunch of factories?

In the code below, I am trying to inject a ViewModel into a View, while the ViewModel requires a Model to wrap and another service that is in the container. The Model is not registered as it is not really a "service".
How do I:
a) not have to provide the IService instance as an argument (let the container resolve it),
b) not have to register a factory for my ViewModels (there will be many)
So what I'm really asking the container to do is treat my Model (that I pass as an argument) as if it were a registered "service" for the duration of this call to GetInstance.
If this is not possible with LightInject, are there any containers out there that have something like this?
public static class Program
{
public static void Main()
{
var container = new LightInject.ServiceContainer();
var service = new Service1();
container.RegisterInstance<IService>(service);
// Have to register the factory
container.Register<IService, PersonModel, PersonViewModel>(
(f, s, p) => new PersonViewModel(s, p));
container.Register<View>();
var person = new PersonModel(); // this is contextual -- not a service.
object view = CreateView(container, typeof(View), service, person);
// ultimate desired code:
//var view = container.GetInstance(typeof(View), new object[] { person });
}
private static object CreateView(ServiceContainer container, Type viewType, IService service, object model)
{
var ctor = viewType.GetConstructors()[0];
var parameters = new List<object>();
foreach (var param in ctor.GetParameters())
{
var attr = param.GetCustomAttributes(typeof(ModelAttribute), false).FirstOrDefault();
if (model != null && attr != null)
{
parameters.Add(model);
}
else
{
parameters.Add(container.GetInstance(param.ParameterType, new object[] { service, model }));
}
}
return Activator.CreateInstance(viewType, parameters.ToArray());
}
}
public interface IService
{
}
public class Service1 : IService
{
}
public class PersonModel
{
}
public class PersonViewModel
{
public PersonModel PersonModel { get; set; }
public PersonViewModel(IService service, [Model] PersonModel person)
{
PersonModel = person;
}
}
public class View
{
public PersonViewModel PersonViewModel { get; set; }
public View(PersonViewModel vm)
{
PersonViewModel = vm;
}
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class ModelAttribute : Attribute
{
}
I have solved the issues with a combination of techniques...
a) use a Scope and register the ViewModel and View with PerScopeLifetime.
b) use a "ModelTracker" registered with a factory to allow an instance not created by the container to be injected (since models will be created by client code or a DbContext).
This combination also allows me to not register a factory for every ViewModel type -- but instead use the built-in mass registration functions (like RegisterAssembly).
public static class Program
{
public static void Main()
{
var container = new LightInject.ServiceContainer();
container.RegisterInstance<IService>(new Service1());
container.Register<View>(new PerScopeLifetime());
container.Register<PersonViewModel>(new PerScopeLifetime());
container.Register<ModelTracker>(new PerScopeLifetime());
container.Register<PersonModel>((f) => (PersonModel)f.GetInstance<ModelTracker>().Instance);
using (var scope = container.BeginScope())
{
var tracker = scope.GetInstance<ModelTracker>();
tracker.Instance = new PersonModel() { Name = "person1" };
var view = scope.GetInstance<View>();
}
}
}
public class ModelTracker
{
public object Instance { get; set; }
}
public class PersonModel
{
public string Name { get; set; }
}
public class PersonViewModel
{
private readonly IService service;
private readonly PersonModel person;
public PersonViewModel(IService service, PersonModel person)
{
this.service = service;
this.person = person;
}
}
public class View
{
public PersonViewModel PersonViewModel { get; set; }
public View(PersonViewModel vm)
{
PersonViewModel = vm;
}
}
public interface IService { }
public class Service1 : IService { }

Troubles with dependency injection

I am working on an ASP.NET WebAPI using OWIN. To manage the instances of DBContext (Entity Framework), I try to use Ninject. However, when I call a controller, the programm returns an error:
The controller cannot be created, missing constructor.
Could you tell me what is going wrong here?
My Controller Class:
public class Testcontroller
{
private IApplicationDbContext _context;
public Testcontroller(IApplicationDbContext context)
{
_context = context;
}
}
This is the Ninject-File:
public static class NinjectWebCommon
{
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();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
kernel.Bind<IApplicationDbContext>().To<ApplicationDbContext>();
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
private static void RegisterServices(IKernel kernel)
{
}
}
Ninject Dependency Scope:
public class NinjectDependencyScope : IDependencyScope
{
IResolutionRoot resolver;
public NinjectDependencyScope(IResolutionRoot resolver)
{
this.resolver = resolver;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has been disposed");
return resolver.TryGet(serviceType);
}
public System.Collections.Generic.IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has been disposed");
return resolver.GetAll(serviceType);
}
public void Dispose()
{
IDisposable disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
}
// This class is the resolver, but it is also the global scope
// so we derive from NinjectScope.
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
IKernel kernel;
public NinjectDependencyResolver(IKernel kernel) : base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
The Entity Framework DbContext-Class:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
}
public virtual DbSet<Models.Team> Teams { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
public interface IApplicationDbContext
{
DbSet<Models.Team> Teams { get; set; }
int SaveChanges();
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}
I tried to follow this tutorial: http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api
What have I done wrong here?
Thanks in advance!
Unless there was a serious omission in you controller code, your controller is not inheriting from ApiController, as is expected with Web Api
public class TestController : ApiController {
private IApplicationDbContext _context;
public Testcontroller(IApplicationDbContext context) {
_context = context;
}
}
UPDATE
I tried to set up everything from scratch using this: http://www.alexzaitzev.pro/2014/11/webapi2-owin-and-ninject.html
For some reason, it now works out perfectly fine.
Thank you for your support!

Instance in Caliburn Micro

We are using Caliburn Micro for the first time.
We have a AppBootstrapper inherited from ShellViewModel.
Situvation is that VieModels should have the same instance unless it is reset.
we are able to achieve shared or not shared everytime, but releasing the export whenever needed is still a mystery.
public class AppBootstrapper : Bootstrapper<ShellViewModel>
{
private static CompositionContainer _container;
protected override void Configure()
{
try
{
_container = new CompositionContainer(
new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x))));
var batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(_container);
StyleManager.ApplicationTheme = ThemeManager.FromName("Summer");
_container.Compose(batch);
}
catch (Exception exception)
{
}
}
public static void ReleaseAll()
{
}
protected override object GetInstance(Type serviceType, string key)
{
try
{
var contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
var exports = _container.GetExportedValues<object>(contract);
if (exports.Any())
return exports.First();
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
}
catch (ReflectionTypeLoadException ex)
{
foreach (Exception inner in ex.LoaderExceptions)
{
// write details of "inner", in particular inner.Message
}
return null;
}
}
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
try
{
return _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
}
catch (Exception exception)
{
return null;
}
}
protected override void BuildUp(object instance)
{
_container.SatisfyImportsOnce(instance);
}
}
ShellViewModel
[Export(typeof(ShellViewModel))]
public sealed class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<object>
{
[ImportingConstructor]
public ShellViewModel(CompositionContainer compositionContainer, IEventAggregator eventAggregator)
{
CompositionContainer = compositionContainer;
EventAggregator = eventAggregator;
eventAggregator.Subscribe(this);
Items.Add(compositionContainer.GetExportedValue<AViewModel>());
Items.Add(compositionContainer.GetExportedValue<BViewModel>());
ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.A.ToString()));
}
public IEventAggregator EventAggregator { get; set; }
public CompositionContainer CompositionContainer { get; set; }
public void Handle(object message)
{
//throw new System.NotImplementedException();
}
public void B()
{
ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.B.ToString()));
}
public void A()
{
ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.A.ToString()));
}
public void RESET()
{
AppBootstrapper.ReleaseAll();
ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.A.ToString()));
}
public enum AppMessageType
{
A,
B
}
}
AViewModel
[Export(typeof(AViewModel))]
public sealed class AViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<object>
{
[ImportingConstructor]
public AViewModel(CompositionContainer compositionContainer, IEventAggregator eventAggregator)
{
DisplayName = ShellViewModel.AppMessageType.A.ToString();
CompositionContainer = compositionContainer;
EventAggregator = eventAggregator;
eventAggregator.Subscribe(this);
}
public IEventAggregator EventAggregator { get; set; }
public CompositionContainer CompositionContainer { get; set; }
public void Handle(object message)
{
//throw new System.NotImplementedException();
}
}
BViewModel
[Export(typeof(BViewModel))]
public sealed class BViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<object>
{
[ImportingConstructor]
public BViewModel(CompositionContainer compositionContainer, IEventAggregator eventAggregator)
{
DisplayName = ShellViewModel.AppMessageType.B.ToString();
CompositionContainer = compositionContainer;
EventAggregator = eventAggregator;
eventAggregator.Subscribe(this);
}
public IEventAggregator EventAggregator { get; set; }
public CompositionContainer CompositionContainer { get; set; }
public void Handle(object message)
{
//throw new System.NotImplementedException();
}
}
Now AViewModel and BViewModel have single instance.
Whenever Release Button is clicked i want to have new instance of AViewModel and BViewModel.
Hoping to get a reply soon.
Regards,
Vivek
When working with an IoC container, the only part of your code that should take it as a dependency should be your composition root (i.e. your AppBootstrapper in this case). You shouldn't be injecting or referencing the container anywhere else in your code (except possibly factories).
If you want your ShellViewModel to control the lifetime of your child view models (A and B), then you should consider injecting view model factories into your ShellViewModel (via constructor injection if they are required dependencies).
Your AViewModelFactory would just have a single Create method that returns a new instance of AViewModel, likewise with the BViewModelFactory. You can simply new up your view models directly in the factories. If your view models have large dependency chains themselves, then you could consider adding a reference to your container in the factories, although preferably consider looking into the MEF ExportFactory<T> type.

how to reference controller function from another controller

Trying to learn ASP MVC coming from Linux/LAMP background (in other words I'm a newb) ...
For some reason I can't seem to use a function defined in a controller in another controller.
Here's the function in my MessagesController.cs file:
public List<Message> GetMessagesById(string username)
{
return db.Messages.Where(p => p.user == username).ToList();
}
When I try to reference it:
using LemonadeTrader.Models;
using LemonadeTrader.Controllers; // added this to pull the Messages::getMesssagesById
...
ViewBag.messages = lemondb.Messages.GetMessagesById(Membership.GetUser().ProviderUserKey.ToString());
I get something along the lines of lemondb.Messages does not contain a method called GetMesssagesById.
How do I reference it?
You shouldn't be linking controller methods like this, not to mention that controllers shouldn't be performing data access directly. I would recommend you externalizing this function into a separate class/repository which could be used by both controllers.
Example:
public class MessagesRepository
{
public List<Message> GetMessagesById(string username)
{
return db.Messages.Where(p => p.user == username).ToList();
}
}
and then:
public class FooController: Controller
{
public ActionResult Index()
{
var db = new MessagesRepository()
ViewBag.messages = db.GetMessagesById(Membership.GetUser().ProviderUserKey.ToString());
return View();
}
}
public class BarController: Controller
{
public ActionResult Index()
{
var db = new MessagesRepository()
ViewBag.messages = db.GetMessagesById(Membership.GetUser().ProviderUserKey.ToString());
return View();
}
}
OK, that's the first step. This code could be improved by decoupling the controllers from the repository by introducing an abstraction for this repository:
public interface IMessagesRepository
{
List<Message> GetMessagesById(string username);
}
public class MessagesRepository: IMessagesRepository
{
public List<Message> GetMessagesById(string username)
{
return db.Messages.Where(p => p.user == username).ToList();
}
}
then you could use constructor injection for those controllers:
public class FooController: Controller
{
private readonly IMessagesRepository _repository;
public class FooController(IMessagesRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
ViewBag.messages = _repository.GetMessagesById(Membership.GetUser().ProviderUserKey.ToString());
return View();
}
}
public class BarController: Controller
{
private readonly IMessagesRepository _repository;
public class BarController(IMessagesRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
ViewBag.messages = _repository.GetMessagesById(Membership.GetUser().ProviderUserKey.ToString());
return View();
}
}
finally you would configure your DI framework to pass the corresponding implementation into those controllers.
I would also recommend you replacing this ViewBag with a strongly typed view model:
public class MyViewModel
{
public List<Message> Messages { get; set; }
}
and then:
public ActionResult Index()
{
var model = new MyViewModel
{
Messages = _repository.GetMessagesById(Membership.GetUser().ProviderUserKey.ToString())
};
return View(model);
}
Place GetMessageById (and all other methods needed for accessing messages) to separate class and use the class everywhere you need to get Message data.
MessageService service = new MessageService();
ViewBag.messages = service.GetMessagesById(...);

MEF Custom attributes and Lazy

I think I am losing my mind. :)
I've been struggling with this for two days now. The code looks right. But for some reason when I try to access the [ImportMany] field, it is null, or at least not returning any values.
It get the 3 parts in the catalog, but they don't get applied to the Lazy[] import I am defining.
Here's my code:
using System;
using System.Linq;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace MefTest
{
// Extension interface and metadata
public interface IUIExtension
{
void DoSomething();
}
public interface IUIExtensionDetails
{
string Name { get; }
string Uri { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class UIExtensionAttribute : ExportAttribute
{
public UIExtensionAttribute() : base(typeof(IUIExtensionDetails)) { }
public string Name { get; set; }
public string Uri { get; set; }
}
// Extensions
[UIExtension(Name="Test 01", Uri="http://www.yourmomma.com/")]
public class Test1Extension : IUIExtension
{
public void DoSomething() { }
}
[UIExtension(Name = "Test 02", Uri = "http://www.yourdaddy.com/")]
public class Test2Extension : IUIExtension
{
public void DoSomething() { }
}
[UIExtension(Name = "Test 03", Uri = "http://www.youruncle.com/")]
public class Test3Extension : IUIExtension
{
public void DoSomething() { }
}
// Main program
public class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
[ImportMany]
public Lazy<IUIExtension, IUIExtensionDetails>[] Senders { get; set; }
public void Run()
{
Compose();
}
public void Compose()
{
var catalog = new AssemblyCatalog(
System.Reflection.Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
// This is always 3
Console.WriteLine(
(from g in container.Catalog.Parts select g).Count());
// This is always 0
Console.WriteLine(Senders.Length);
Console.ReadKey();
}
}
}
Your error is here:
public UIExtensionAttribute() : base(typeof(IUIExtensionDetails))
You should pass the contract type there, not the metadata type:
public UIExtensionAttribute() : base(typeof(IUIExtension))
(Also, in order to make sure that your custom export class has the right properties as expected by the import with metadata, I would make it implement the IUIExtensionDetails interface. But that is not mandatory.)
Your metadata attribute is defining the exports as typeof(IUIExtensionDetails) which is your metadata contract, not your actual extension. Change the custom attribute constructor to:
public UIExtensionAttribute() : base(typeof(IUIExtension)) { }