Xamarin Android: how to implement a ViewModelProvider factory? - xamarin.android

I'm trying to create a viewmodel provider factory and I'm little bit lost. I've already added the required Nuget packages and my view models extend the AndroidViewModel type. Now, I'd like to create a factory that would use autofac to create the required view models from the OnCreate activitie's method. The creation call looks like this:
_viewModel = (ViewModelProviders.Of(this, _viewModelFactory)
.Get(Java.Lang.Class.FromType(typeof(MainActivityViewModel))) as JavaObjectWrapper<MainActivityViewModel>)
.Object;
Now, the factory:
public class ViewModelFactory : ViewModelProvider.AndroidViewModelFactory {
public ViewModelFactory(Application application) : base(application) {
}
public override Object Create(Class modelClass) {
// TODO: any way to get the .NET type that was passed here?
return base.Create(modelClass);
}
}
Can I retrieve the .NET type (MainActivityViewModel) from the Class instance that is passed into the Create method call (the type would be required to resolve it from the autofac container)? If there is, how can I do that?
Thanks.

This is how I do this with Unity, but this pattern can be used for passing anything through the ViewModel constructor:
The ViewModel itself
public class HomeViewModel : ViewModel
{
IUnityContainer _unityContainer;
public HomeViewModel(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
}
The HomeViewModelFactory (Default constructor required)
public class HomeViewModelFactory : Java.Lang.Object, ViewModelProvider.IFactory
{
IUnityContainer _unityContainer;
public HomeViewModelFactory()
{
}
public HomeViewModelFactory(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public Java.Lang.Object Create(Class p0)
{
return _unityContainer.Resolve<HomeViewModel>();
}
}
Usage in Fragment
public override void OnActivityCreated(Bundle savedInstanceState)
{
base.OnActivityCreated(savedInstanceState);
var homeViewModelFactory = _unityContainer.Resolve<HomeViewModelFactory>();
_homeViewModel = ViewModelProviders.Of(this, homeViewModelFactory).Get(Java.Lang.Class.FromType(typeof(HomeViewModel))) as HomeViewModel;
}

Related

How does IoC container know which named instance to inject?

When there are multiple named implementations for a given interface, how does the container (I am using Unity in a Prism application) know which one to inject unless I call the container.Resolve with the registered name? Here is a simple example:
public interface IDependencyClass
{
void DoSomething();
}
public class DependencyClassA : IDependencyClass
{
void DoSomething() { }
}
public class DependencyClassB : IDependencyClass
{
void DoSomething() { }
}
public interface IConsumer
{
void TakeUserSpecificAction();
}
public class Consumer : IConsumer
{
IDependencyClass dependencyInstance;
public Consumer(IDependencyClass _dependencyInstance)
{
dependencyInstance = _dependencyInstance;
}
public void TakeUserSpecificAction()
{
dependencyInstance.DoSomething();
}
}
public class MyBootStrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType<IDependencyClass, DependencyClassA>( "InstanceA" );
Container.RegisterType<IDependencyClass, DependencyClassB>( "InstanceB" );
Container.RegisterType<IConsumer, Consumer>();
}
}
and here is my MainViewModel from my application. The "RaiseSomeCommand" command is not enabled until the user has logged in. When it is enabled, it can execute the ReaiseConsumerCommandRequest, which in turn calls the consumer. Here is my ViewModel.
public class MainWindowViewModel
{
private readonly IRegionManager regionManager;
private readonly ILoginService loginService;
private readonly IConsumer consumer;
public ICommand RaiseSomeCommand { get; set; }
public MainWindowViewModel( IRegionManager regMgr, ILoginService _loginService, IConsumer _consumer )
{
regionManager = regMgr;
loginService = _loginService;
consumer = _consumer;
NavigateCommand = new DelegateCommand<string>( Navigate );
LoginViewRequest = new InteractionRequest<INotification>();
RaiseSomeCommand = new DelegateCommand( RaiseConsumerCommandRequest );
}
private void RaiseConsumerCommandRequest()
{
consumer.TakeUserSpecificAction();
}
}
So, when I execute
consumer.TakeUserSpecificAction();
which DependencyClass instance am I using? DependencyClassA or DependencyClassB. Also, If I want to use specifically say DependencyClassB, What do I need to do to make it happen. I don't want to call
container.Reslove<IDependencyClass>("InstanceB")
in my ViewModel because I am then using the container as a service locator. I am also passing the container reference around.
I have seen in some code examples that the constructor parameter for the consumer class is decorated with a Dependency attribute like below.
public class Consumer
{
IDependencyClass dependencyInstance;
public Consumer([Dependency("InstanceB")]IDependencyClass _dependencyInstance)
{
dependencyInstance = _dependencyInstance;
}
}
But then, I am putting a hard constraint on the Consumer to use only the "InstanceB" implementation. Secondly, I am creating a dependency to Unity. Thirdly, now I have to clone the Consumer class to use "InstanceA" Implementation. That goes against the DRY principle.
I have heard that these conditions are application decisions and not an IoC related logic. I can agree with that argument. But then, where and how in the application would I resolve the right implementation without violating one rule or another?
I can't see how I can inject the right concrete instance unless I choose to use one of the above two options. Container.Resolve or Dependency attribute. Can anybody help please?

Windsor Typed Factory with Open Generic Interface

In my application, I want to take dependencies on multiple repositories in a class, where not all of them are required each time. Rather than constructing an instance of each one where unnecessary, I use the Typed Factory facility in Windsor.
However, registering a factory for each repository is a bit tiresome, and I would like to replace this with an open generic registration. What I want to do is something like the following:
container.Register(
Component.For<IFactory<IRepository<>>>().AsFactory()
);
However, this is a syntax error because of the missing type parameter for IRepository. Is there a syntax I can use which would make this work?
NB: I'm aware that I can register an untyped Factory interface and use this to create multiple components. I'm not interested in doing this as this is essentially taking a dependency on a service locator - if I've not registered a dependency then I won't know about it until the code tries to use it - with my approach I know about this in the constructor even though I'm not creating an instance yet.
Full (simplified) sample below:
public class TestA { }
public class TestB { }
public interface IRepository<T> { T Create(); }
public class Repository<T> : IRepository<T>
{
public T Create() { return Activator.CreateInstance<T>(); }
}
public interface IFactory<T>
{
T Create();
void Release(T instance);
}
class Program
{
static void Main(string[] args)
{
IWindsorContainer container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
// Individual registrations of repositories here are fine
Component.For<IRepository<TestA>>().ImplementedBy<Repository<TestA>>(),
Component.For<IRepository<TestB>>().ImplementedBy<Repository<TestB>>()
);
container.Register(
// Individual registrations of factories - works, but trying to avoid!
Component.For<IFactory<IRepository<TestA>>>().AsFactory(),
Component.For<IFactory<IRepository<TestB>>>().AsFactory()
);
container.Register(
// Generic Registration of Factories - syntax errors
// Component.For<IFactory<IRepository<>>>().AsFactory()
// Component.For(typeof(IFactory<IRepository<>>)).AsFactory()
);
var factoryA = container.Resolve<IFactory<IRepository<TestA>>>();
var factoryB = container.Resolve<IFactory<IRepository<TestB>>>();
var repoA = factoryA.Create();
var repoB = factoryB.Create();
Console.WriteLine("Everything worked");
}
}
Your factory inteface definition is a little too "open". Change your factory interface as follows:
public interface IRepositoryFactory<T>
{
IRepository<T> Create();
void Release(IRepository<T> instance);
}
And you can then register:
container.Register(Component.For(typeof(IRepositoryFactory<>)).AsFactory());
And resolve:
var factoryA = container.Resolve<IRepositoryFactory<TestA>>();
var factoryB = container.Resolve<IRepositoryFactory<TestB>>();
There's a pattern for grouping repositories together. It is called unit of work. So, instead of creating a factory for creating repositories, create a unit of work class that references these repositories. For instance:
public abstract class UnitOfWork : IDisposable
{
// here is your factory
protected abstract IRepository<T> GetRepository<T>();
public IRepository<User> Users
{
get { return this.GetRepository<User>();
}
public IRepository<Customer> Customers
{
get { return this.GetRepository<Customer>();
}
// etc..
}
In your Composition Root you can define an UnitOfWork implementation that holds a reference to Windsor and enables you to get IRepository<T> implementations:
internal sealed class WindsorUnitOfWork : UnitOfWork
{
private WindsorContainer container;
public WindsorUnitOfWork(WindsorContainer container)
{
this.container = container;
}
protected override IRepository<T> GetRepository<T>()
{
return this.container.Resolve<IRepository<T>>();
}
}
And register it as follows:
container.Register(Component.For<UnitOfWork>()
.ImplementedBy<WindsorUnitOfWork>()
.LifeStyle.Transient);
Consumers now have a really convenient way of using the repositories:
private readonly UnitOfWork db;
public KarmaService(UnitOfWork db)
{
this.db = db;
}
public int CalculateKarmaForActiveUsersByName(string name)
{
var users =
from user in this.db.Users
where user.Name == name
where user.Active
select user;
return users.Sum(user => user.Karma);
}

How to avoid repositories that duplicate code

I have successfully setup a simple mvc application that lists teams. I'm using Ninject to inject the appropriate repository depending on the controller (thanks to stack overflow ;). All looks good, except that the repository code looks exactly the same. And I know that's wrong. So my TeamRepository has two classes (for now).
public class SwimTeamRepository : ITeamRepository<SwimTeam>
{
private readonly Table<SwimTeam> _teamTable;
public SwimTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SwimTeam>());
}
public IQueryable<SwimTeam> Team
{
get { return _teamTable; }
}
}
public class SoccerTeamRepository : ITeamRepository<SoccerTeam>
{
private readonly Table<SoccerTeam> _teamTable;
public SoccerTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SoccerTeam>());
}
public IQueryable<SoccerTeam> Team
{
get { return _teamTable; }
}
}
They look exactly the same except for the Class and Table name, so clearly I need to re-factor this. What would be the best approach here? Singleton? Factory Method?
Thanks in advance!
You could use generics:
public interface ITeamRepository<T>
{
}
public class TeamRepository<TTeam> : ITeamRepository<TTeam>
where TTeam : Team
{
private readonly Table<TTeam> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<TTeam>());
}
public IQueryable<TTeam> Team
{
get { return _teamTable; }
}
}
public class Team
{
}
public class SwimTeam : Team
{
}
Then use it like so...
public void MyMethod()
{
var repository = new TeamRepository<SwimTeam>();
}
...and set up your IoC container w/ Ninject like so...
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<ITeamRepository<SwimTeam>>
.To<TeamRepository<SwimTeam>>();
}
}
public void MyMethod()
{
var repository = kernel.Get<ITeamRepository<SwimTeam>>();
}
If you want to get REAL generic and have a single repository for ALL of your mapped classes, you can do something like this:
public interface IRepository
{
IQueryable<T> Get<T>() where T : class, new();
}
public class Repository : IRepository, IDisposable
{
private DataContext _dataContext;
public Repository(string connectionString)
{
_dataContext = new DataContext(connectionString);
}
public IQueryable<T> Get<T>()
where T : class, new()
{
return _dataContext.GetTable<T>().AsQueryable();
}
public void Dispose()
{
if (_dataContext != null)
{
_dataContext.Dispose();
_dataContext = null;
}
}
}
...which you could call like so (after setting up your Ninject container)...
using (var repository = kernel.Get<IRepository>())
{
var swimTeam = repository.Get<SwimTeam>();
}
Since Ninject takes care of the life-cycle management of your objects, you don't HAVE to wrap the repository in a using statement. In fact, you don't want to use a using statement there at all if you plan to use the repository more than once within the scope of its lifetime. Ninject will automatically dispose of it when it's life-cycle ends.
Here's a good article by Rob Conery on using this kind of technique to reduce the friction of using different ORMs.
EDIT by keeg:
I Think
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : Team {}
Should be
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : class {}
Please correct if I'm wrong.
Is this what you want?
public class TeamRepository : ITeamRepository<T>
{
private readonly Table<T> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<T>());
}
public IQueryable<T> Team
{
get { return _teamTable; }
}
}

How to configure ObjectFactory to call parameterized constructor structuremap

PLEASE: If my question isn't clear, please tell me and I'll try to rephrase it
I need [Default Constructor] in LogOnModel, so it can't be removed.
LoadModel+ModelFactory and LogOnModel are physically in different files in different projects AND project2 has reference to project1 and NOT vice versa.
1 - Let say that
type=typeof(LogOnModel). When ObjectFactory.GetInstance(t) is called I want it to call the
parameterized constructor of LogOnModel and pass it the #params
2 - If I'll add to the parameterized constructor of LogOnModel another parameter,for example
public LogOnModel(string param, IPageService pageService)
so ObjectFacytory should call this constructor without any problems
How to configure/initiate ObjectFactory, so this will work?
Thank you
EDITED
//Project1/file1.cs
public void LoadModel(Type type, string param)
{
var factory = new ModelFactory();
var model = factory.Get(type, **param**);
}
public class ModelFactory : IModelFactory
{
public PageModel Get(Type t, **string param**)
{
//NOW I NEED SOMEHOW TO PASS **param** TO EVERY INSTANCE THAT INHERITS FROM **PageModel**
return ObjectFactory.GetInstance(t) as PageModel;
}
}
//Project2/file2.cs
public class LogOnModel : PageModel
{
public LogOnModel()
{
}
public LogOnModel(string param)
{
}
}
public class Model2 : PageModel
{
public LogOnModel()
{
}
public LogOnModel(string param)
{
}
}
public class Model3 : PageModel
{
public LogOnModel()
{
}
public LogOnModel(string param)
{
}
}
StructureMap will use the constructor with the most parameters by default, so that part is easy. Then you just need to configure the value of param like so:
ObjectFactory.Initialize(i => {
i.For<LogOnModel>().Use<LogOnModel>();
});
When you call the container, use the with method to pass in your parameter:
return ObjectFactory.With("param").EqualTo(param).GetInstance(t) as PageModel;

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