Injection of Repository into ShellViewModel, via Bootstrapper OnStartUp - c#

I'm stuck!
I'm using Caliburn.micro to take away some of the pain implementing MVVM in a WPF application.
Currently I only have a single View / ViewModel, but in the future there could be several ViewModels. The current ViewModel is using a Repository to populate a list of objects:
public class ShellViewModel : Screen
{
private IMyObjectRepository<IMyObject> _myObjectsRepo = null;
private BindableCollection<MyObject> _myObjects;
private string _connString;
/// <summary>
/// constructor
/// </summary>
public ShellViewModel()
{
//call the method which sets up the repository
GetMyObjectsRepository();
//following three lines cast the list from type IReport to type Report
var IMyObjects= _myObjectsRepo.GetAllIMyObjects();
var myObjects = IMyObjects.OfType<MyObject>().ToList();
MyObjects = new BindableCollection<MyObject>(myObjects );
}
private void GetMyObjectsRepository()
{
_connString = ConfigurationManager.ConnectionStrings["xxx"].ConnectionString;
_myObjectRepo = MyObjectRepositoryFactory.InstantiateRepo(_connString);
}
The above smells like a future problem - if I create a different ViewModel which has its own attribute of BindableCollection<MyObject> _myObjects; then the two collections, of the same objects, could quickly have different states i.e. ObjectX in the first ViewModel might change its name attribute, but ObjectX still has its original name in the second ViewModel.
I was thinking I could inject this list of <MyObject> into the ViewModel when it is constructed - should I do this in Bootstrapper.cs? (I'd rather avoid full blown DI as this is a small project)
Currently Bootstrapper.cs looks like the following - how do I move some of the logic in the above code snippet into here? Does it go in the OnStartUp event method? If so then how?
using Caliburn.Micro;
using Prototype_WPF.ViewModels;
using System.Windows;
namespace Prototype_WPF
{
public class Bootstrapper: BootstrapperBase
{
public Bootstrapper()
{
Initialize();
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
}
}

You could use the Handler method to register factory methods for your view models in the bootstrapper:
public class Bootstrapper : BootstrapperBase
{
private readonly BindableCollection<MyObject> _myObjects = new BindableCollection<MyObject>();
private SimpleContainer container;
public Bootstrapper()
{
Initialize();
}
protected override void Configure()
{
container = new SimpleContainer();
container.Singleton<IWindowManager, WindowManager>();
container.Handler<ShellViewModel>(_ => new ShellViewModel(_myObjects));
container.Handler<SomeOtherViewModel>(_ => new SomeOtherViewModel(_myObjects));
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor(typeof(ShellViewModel));
}
protected override object GetInstance(Type service, string key)
{
return container.GetInstance(service, key);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
container.BuildUp(instance);
}
}

You can create a separate component for retrieving your objects, something like IMyObjectService and implement it.
public interface IMyObjectService
{
IList<MyObject> GetMyObjects();
}
Than create an overload of Configure method in Bootstrapper and register an implementation, something like that:
protected override void Configure()
{
container = new SimpleContainer();
container.Singleton<IMyObjectService, MyObjectService>();
//other registrations
container.PerRequest<ShellViewModel>();
}
And finally use a constructor injection for any ViewModel to inject and use this service. The Caliburn.Micro documentation already has some examples

You can 'Register' the service and 'Register' every class like below
protected override void Configure()
{
container = new SimpleContainer();
container.Instance(container);
container
.Singleton<IMyObjectService, MyObjectService>();
//Register all ViewModel classes
GetType().Assembly.GetTypes()
.Where(type => type.IsClass)
.Where(type => type.Name.EndsWith("ViewModel"))
.ToList()
.ForEach(viewModleType => container.RegisterPerRequest(
viewModleType, viewModleType.ToString(), viewModleType));
}

Related

Creating ViewModels using MEF in a MVVM

This is going to be a bit lengthy, so hold on tight.
I have a project that uses Caliburn.Micro to implement MVVM pattern. For IoC, I am using MEF. All the ViewModels are marked with attribute [Export(typeof(IScreen))] . IScreen is defined in Caliburn.Micro.
In my BootStrapper file I have set up MEF like so:
private CompositionContainer container;
protected override void Configure()
{
//Set up MEF
container = new CompositionContainer(new AggregateCatalog``AssemblySource.Instance.Select``(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));
var batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(container);
container.Compose(batch);
//Other stuff
}
Now, I show the first ViewModel using
protected override void OnStartup(object sender, StartupEventArgs e) => DisplayRootViewFor<ViewModels.Main.MainViewModel>();
All that is fine and dandy. Now, the problem starts when I want to switch from one ViewModel to another.
An example of a ViewModel is :
[PartCreationPolicy(CreationPolicy.NonShared), Export(typeof(IScreen))]
sealed class SampleViewModel: ScreenVMwithUoW<IAddItemUoW>
{
[ImportingConstructor]
public SampleViewModel(IAddItemUoW uow, IEventAggregator eventAggregator) : base(uow, eventAggregator)
{
}
//bla bla bla
}
Let's say I want to open SampleViewModel and close my MainViewModel. How do I do it using MEF?
Here is what I am doing now:
[Export(typeof(IScreenFactory))]
class ScreenFactory : IScreenFactory
{
private Dictionary<Type, ExportFactory<IScreen>> _screenDictionary { get; set; }
private IEnumerable<ExportFactory<IScreen>> _screenfactoryCollection { get; set; }
private ExportLifetimeContext<IScreen> _currentScreenLifeTimeCtx { get; set; }
[ImportingConstructor]
public ScreenFactory([ImportMany(AllowRecomposition = true)] IEnumerable<ExportFactory<IScreen>> screenList)
{
_screenfactoryCollection = screenList;
_reportfactoryCollection = reportsList;
}
public IScreen GetScreen(Type t)
{
if (_screenDictionary == null)
{
PopulateScreenDictionary(_screenfactoryCollection);
}
_currentScreenLifeTimeCtx = _screenDictionary[t].CreateExport();
return _currentScreenLifeTimeCtx.Value;
}
private void PopulateScreenDictionary(IEnumerable<ExportFactory<IScreen>> screenfactories)
{
_screenDictionary = screenfactories.ToDictionary(c => c.CreateExport().Value.GetType(), c => c);
}
public void DisposeCurrentScreenContext()
{
_currentScreenLifeTimeCtx?.Dispose();
}
public void Dispose()
{
DisposeCurrentScreenContext();
}
}
Whenever I need a new instance of a ViewModel, I just do:
DeactivateItem(ActiveItem, true);
_vmFactory.DisposeCurrentScreenContext();
ActivateItem(_vmFactory.GetScreen(NextViewModelName));
This CANNOT be the normal way to do so. Also, this also adds a huge hit in performance, especially the startup time of the application, when the number of ViewModels increase to about 25-30.
I would also like to avoid the Service Locator Pattern, if possible. I am also open to using a proper IoC Container instead of MEF, but MEF allows me to add ViewModels with very little effort. Just adding the annotation [Export(typeof(IScreen))] does the job.

Property Injection (setter injection) Prism for Xamarin.Forms

Is the setter injection supported in the Xamarin.forms?
I have a service injected in the bootstrapper like this
Container.RegisterType<ICommonService, CommonService>();
And inside a viewmodel, I want to have an instance injected to a property like this
[Dependency]
public ICommonService CommonService { get; set; }
But in the runtime, the property CommonService is always null.
The attribute I used is the Microsoft.Practices.Unity.DependencyAttribute, not Xamarin.Forms.DependencyAttribute
If I inject inside the constructor, it works
public LandingPageViewModel(INavigationService navigationService, ICommonService commonService)
Edited: added code snippet
public class Bootstrapper : UnityBootstrapper
{
protected override Page CreateMainPage()
{
try
{
return Container.Resolve<Views.LandingPage>();
}
catch (Exception exception)
{
//TODO: intent to get exception info
throw;
}
}
protected override void RegisterTypes()
{
DependencyResolver.Instance.Initialize(Container);
this.RegisterViews();
this.RegisterServices();
this.RegisterSingleton();
}
private void RegisterViews()
{
Container.RegisterTypeForNavigation<LandingPage>();
Container.RegisterTypeForNavigation<Page1>();
}
private void RegisterServices()
{
Container.RegisterType<ICommonService, CommonService>();
}
private void RegisterSingleton()
{
}
}
public partial class App : Application
{
public App()
{
InitializeComponent();
var bootstrapper = new Bootstrapper();
bootstrapper.Run(this);
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
Hmm they removed the DependencyAttribute injection feature since Prism 7.0, I think we should register it manually. (your code snippet should work)
Look: https://brianlagunas.com/whats-new-in-prism-for-xamarin-forms-7-0/

Why Won't Ninject New Up Objects In A Class

My Setup:
Visual Studio 2013
Web Forms/MVC project
C#
Ninject 3.2.0.0
Entity Framework
I have a Web Forms/MVC hybrid project that uses Ninject for its IoC containter. I've no problems with Ninject until today. The problem I ran into is that I can't get Ninject to new up some objects whenever I use a class. Here is some code that works:
// Master1.master
namespace TestCode
{
public partial class Master1 : MasterPage
{
[Inject]
public FooController Foo { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
// Do some setup logic.
Foo.Bar();
}
}
}
Now here is some code that doesn't work using a class:
// Master1.master
namespace TestCode
{
public partial class Master1 : MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
new Wrapper().SomeMethod();
}
}
}
// Wrapper.cs
namespace TestCode
{
public class Wrapper
{
[Inject]
public FooController Foo { get; set; }
public void SomeMethod()
{
// Do some setup logic.
Foo.Bar();
}
}
}
My problem is that when I execute SomeMethod(), Foo is null. Why is this and what can I do to get Ninject to new up Foo?
Okay - I got it working now. Thanks everyone! I needed to add a binding my NinjectWebCommon class like so:
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();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
// Needed to add this binding.
kernel.Bind<IWraper>().To<Wraper>().InRequestScope();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
}

ASP.net web forms where to dispose of entity context using UnitOfWork pattern

Throughout my web app I am using a UnitOfWork class to handle all my interactions with the data source. Below is the interface it inherits.
public interface IUnitOfWork : IDisposable
{
ActivityService ActivityService { get; }
AmendmentService AmendmentService { get; }
AspUserService AspUserService { get; }
AttachmentService AttachmentService { get; }
CampaignService CampaignService { get; }
CommentService CommentService { get; }
EventRegistrationService EventRegistrationService { get; }
GroupService GroupService { get; }
InstanceService InstanceService { get; }
void Commit();
}
It inherits Idisposable so i dispose the entity context during the UnitOfWorks Dispose method. However when using this class in my web pages i am never sure whether i should create one UnitOfWork class as a variable of the page like so.
public partial class Members_Request : BasePage
{
UnitOfWork uow = new UnitOfWork();
protected void Page_Load(object sender, EventArgs e)
{
Instance instance = uow.InstanceService.GetById(base.instanceId)
}
protected void Page_PreRender(object sender, EventArgs e)
{
//I don't think disposing here will work in all scenarios
uow.Dispose();
}
private void SomeOtherMethod(string name)
{
Group newGroup = new Group{Name = name}
uow.GroupService.Add(group))
uow.Commit();
}
}
Doing it this way i need to be careful when i dispose for example, if i need the UnitOfWork in the Page_PreRender method but it never gets called becuase the request was a Callback, then my context will never get disposed. I am not sure if i should be disposing it during every method i use it then simply reinitialize it as a new UnitOfWork when i need it again to ensure it is always disposed.
An alternative way which ensures it gets dispose is to create a new UnitOfWork for every method i need it in so the above exmaple would become
public partial class Members_Request : BasePage
{
protected void Page_Load(object sender, EventArgs e)
{
UnitOfWork uow = new UnitOfWork();
Instance instance = uow.InstanceService.GetById(base.instanceId)
uow.Dispose();
}
private void SomeOtherMethod(string name)
{
UnitOfWork uow = new UnitOfWork();
Group newGroup = new Group{Name = name}
uow.GroupService.Add(group))
uow.Commit();
uow.Dispose();
}
}
So my question is how can i ensure that my UnitOfWork is always disposed when i share the same one each request, or should i just be creating many UnitOfWork objects whenever i need them and disposing them straight away. I think a solution by sharing the UnitOfWork would be better as it reducing code bloat.
Edit -- One alternative way i am thinking of doing this is to have this code in my base page
protected UnitOfWork uow = new UnitOfWork();
protected override void OnUnload(EventArgs e)
{
uow.Dispose();
base.OnUnload(e);
}
Then i think i can just use the same instance of uow throughout the lifecycle and know it will always be disposed.
I use this: override dispose in every page
public override void Dispose()
{
if(uow != null)
{
uow.Dispose();
}
base.Dispose();
}
uow is my UnitOfWork

How inject depedency to CompositeControl using Ninject

How to inject dependency into CompositeControl?
I tried the following approach - MyServerControl's Calculate is still null.
Thanks!
public class MyServerControl : CompositeControl
{
private TextBox TextBox1;
private TextBox TextBox2;
private Label Label1;
[Inject] // **** This is null ****
public ICalculate Calculate { get; set; }
protected override void CreateChildControls()
{
TextBox1 = new TextBox {ID = "TextBox1", Text = "1"};
Controls.Add(TextBox1);
TextBox2 = new TextBox {ID = "TextBox2", Text = "2"};
Controls.Add(TextBox2);
var button1 = new Button {ID = "Button1", Text = "Calculate"};
button1.Click += button1_Click;
Controls.Add(button1);
Label1 = new Label {ID = "Label1"};
Controls.Add(Label1);
}
private void button1_Click(object sender, EventArgs e)
{
int value1 = Int32.Parse(TextBox1.Text);
int value2 = Int32.Parse(TextBox2.Text);
Label1.Text = "Result:" + Calculate.Add(value1, value2);
}
}
public interface ICalculate
{
int Add(int x, int y);
}
public class Calculate : ICalculate
{
public int Add(int x, int y)
{
return x + y;
}
}
Default Ninject.Web.Common Bootstrapper from NuGet:
using System.Net.NetworkInformation;
[assembly: WebActivator.PreApplicationStartMethod(typeof(NinjectDemo.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(NinjectDemo.App_Start.NinjectWebCommon), "Stop")]
namespace NinjectDemo.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()
{
IKernel kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICalculate>().To<Calculate>().InSingletonScope();
}
}
}
Updated:
I'm not able to get instance to kernel in Page_Load. Am I missing something?
<my:MyServerControl ID="MyServerControl1" runat="server" />
public partial class Default : Page
{
[Inject]
public ICalculate _calculate { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
kernel.Inject(MyServerControl1); // kernel is not available
}
}
I think you could just use the feature that satisfies dependencies on an existing object. In this particular case, in any context your control is used, you just call
kernel.Inject( myControl );
where myControl is an existing instance of your composite control. This has to be called from the code behind, somewhere in the pipeline where the instance is already created. Page_Load would most probably be fine.
Edit: there are numerous ways to be able to resolve anywhere in your application. You could for example have a global service locator. But since you are using the Bootstrapper, you should be able to resolvd your kernel anywhere
var kernel = (IKernel)Bootstrapper.Container;
Your Default page doesn't know about NinjectWebCommon class existence. It also cannot know about the kernel variable which is a NinjectWebCommon.CreateKernel() method's member. The simplest solution is the following:
public static class NinjectWebCommon
{
...
private static IKernel kernel;
public static IKernel CreateKernel()
{
if(kernel != null)
return kernel;
kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
...
}
public partial class Default : Page
{
[Inject]
public ICalculate _calculate { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
NinjectWebCommon.CreateKernel().Inject(MyServerControl1);
}
}
The other way would be to use Ninject magic. Your application class would probably need to inherit from a class provided by Ninject. In MVC it's a NinjectHttpApplication class, which overrides the bootstrapper. Than you could probably go with Wiktor's answer.
Honestly I don't like that Ninject magic, as it sometimes doesn't work for me and than it's very hard to find out why. In my MVC application I ended up creating my own ConfrollerFactory, which injected the dependencies explicitly. It also may be a pain if you want to change your IOC container.
you need to register your Ioc config, see example:
public static void RegisterIoc(HttpConfiguration config)
{
var kernel = new StandardKernel(); // Ninject IoC
kernel.Bind<IMyService>().To<MyService>();
// Tell WebApi how to use our Ninject IoC
config.DependencyResolver = new NinjectDependencyResolver(kernel);
}
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
this.resolver = resolver;
}
public void Dispose()
{
var disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.GetAll(serviceType);
}
}
Add this class in your App_start folder, and then write in Global.asax.cs:
// Tell WebApi to use our custom Ioc (Ninject)
IocConfig.RegisterIoc(GlobalConfiguration.Configuration);

Categories

Resources