How to configure ObjectFactory to call parameterized constructor structuremap - 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;

Related

Xamarin Android: how to implement a ViewModelProvider factory?

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;
}

Ninject Conditional Self bind to change scope (For Task-scheduler) not working properly?

Within MVC Web Application DbContext binding work properly with InRequestScope()
kernel.Bind<DbContext>().ToSelf().InRequestScope();
kernel.Bind<IUnitOfWork<DbContext>>().To<UnitOfWork<DbContext>>();
But from a Task Scheduler call DbContext in InRequestScope() unable to update Db Table (without any error), until I change Binding to InSingletonScope() OR InThreadScope()
Question: So is their any way change scope to InSingletonScope() / InThreadScope() for a Task Scheduler Call. ?
// For Task Scheduler Call, I tried bellow bind, but not working properly
kernel.Bind<DbContext>().ToSelf()
.When(request => request.Target.Type.Namespace.StartsWith("NameSpace.ClassName"))
.InSingletonScope();
** And probably I miss some thing. Need help.
Code Snippet Updated
#region Commented Code
public EmailTask() : this
( DependencyResolver.Current.GetService<IMessageManager>(),
, DependencyResolver.Current.GetService<IUnitOfWork<DbContext>>()) { }
#endregion
public EmailTask(IMessageManager messageManager, IUnitOfWork<DbContext> unitOfWork)
{
this._messageManager = messageManager;
this._unitOfWork = unitOfWork;
ProcessEmail();
}
public class NonRequestScopedParameter : IParameter { ... }
public void ProcessEmail()
{
var temp = SomeRepository.GetAll();
SendEmail(temp);
temp.Date = DateTime.Now;
SomeRepository.Update(temp);
unitOfWork.Commit();
}
public class ExecuteEmailTask : ITask
{
private readonly IResolutionRoot _resolutionRoot;
private int _maxTries = 5;
public ExecuteEmailTask(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
public void Execute(XmlNode node)
{
XmlAttribute attribute1 = node.Attributes["maxTries"];
if (attribute1 != null && !String.IsNullOrEmpty(attribute1.Value))
{
this._maxTries = int.Parse(attribute1.Value);
}
/// send email messages
var task = _resolutionRoot.Get<EmailTask>(new NonRequestScopedParameter());
}
}
In Web.Config
<ScheduleTasks>
<Thread seconds="60">
<task name="ExecuteEmailTask" type="namespace.ExecuteEmailTask, AssemblyName" enabled="true" stopOnError="false" maxTries="5"/>
</Thread>
</ScheduleTasks>
In Global.asax
protected void Application_Start()
{
/* intialize Task */
TaskConfig.Init();
TaskManager.Instance.Initialize(TaskConfig.ScheduleTasks);
TaskManager.Instance.Start();
}
Ninject Bind Syntax
kernel.Bind<DbContext>().ToSelf().InRequestScope(); // Default bind
kernel.Bind<DbContext>().ToSelf()
.When(x => x.Parameters.OfType<NonRequestScopedParameter>().Any())
.InCallScope(); // For Scheduler
Note: EmailTask class also have SomeReposity as a Constructor Argument.
Queries:-
But what is the bind syntax to resolve TaskScheduler(IResolutionRoot resolutionRoot) ?
What is the configuration code to run TaskScheduler ?
As say to put IFakeDbContext directly into constructor, can this work with IUnitOfWork<FakeDbContext> ?
Problem
Task unable to call with Overloaded Constructor , it is only able to call TaskScheduler default Constructor.
Question 4: Can any way to invoke TaskScheduler(IResolutionRoot resolutionRoot) from TaskScheduler default constructor ?
Sample Code Snippet to create Task & run using System.Threading.Timer
private ITask createTask()
{
if (this.Enabled && (this._task == null))
{
if (this._taskType != null)
{
this._task = Activator.CreateInstance(this._taskType) as ITask;
}
this._enabled = this._task != null;
}
return this._task;
}
Question 5: Can I resolve TaskScheduler(IResolutionRoot resolutionRoot) here ?
Solved
public ExecuteEmailTask() :
this(DependencyResolver.Current.GetService<IResolutionRoot>())
OR
public ExecuteEmailTask() : this(new Bootstrapper().Kernel) { }
public ExecuteEmailTask(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
First of, you should note that InSingletonScope() is usually a bad idea for DbContext's/Sessions. What happens if some other service changes data in the meantime? I would recommend investigating what effects this has.
For the scenario you first described, a correctly formulated .When(...) should work.
As an alternative to the .When(...) binding you could also use a .Named("FooBar") binding.
The constructor of the scheduled task would then need to look like:
ctor(Named["FooBar"] DbContext dbContext);
However, note, that this only (easily) works in case you need to inject the DbContext into a single constructor. If the task features dependencies and these need the same DbContext instance, too, it gets a bit tricker.
Since you updated your answer and say that this is the case, i would recommend an entirely different approach: Using a request parameter as basis for the When(...) condition combined with InCallScope binding. See below for an example.
Brace yourself, this is ab it of code :) The implementation requires the ninject.extensions.NamedScope extension (nuget).
I've also used xUnit and FluentAssertions nuget packages to execute the tests.
public class Test
{
// the two implementations are just for demonstration and easy verification purposes. You will only use one DbContext type.
public interface IFakeDbContext { }
public class RequestScopeDbContext : IFakeDbContext { }
public class CallScopeDbContext : IFakeDbContext { }
public class SomeTask
{
public IFakeDbContext FakeDbContext { get; set; }
public Dependency1 Dependency1 { get; set; }
public Dependency2 Dependency2 { get; set; }
public SomeTask(IFakeDbContext fakeDbContext, Dependency1 dependency1, Dependency2 dependency2)
{
FakeDbContext = fakeDbContext;
Dependency1 = dependency1;
Dependency2 = dependency2;
}
}
public class Dependency1
{
public IFakeDbContext FakeDbContext { get; set; }
public Dependency1(IFakeDbContext fakeDbContext)
{
FakeDbContext = fakeDbContext;
}
}
public class Dependency2
{
public IFakeDbContext FakeDbContext { get; set; }
public Dependency2(IFakeDbContext fakeDbContext)
{
FakeDbContext = fakeDbContext;
}
}
public class TaskScheduler
{
private readonly IResolutionRoot _resolutionRoot;
public TaskScheduler(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
public SomeTask CreateScheduledTaskNow()
{
return _resolutionRoot.Get<SomeTask>(new NonRequestScopedParameter());
}
}
public class NonRequestScopedParameter : Ninject.Parameters.IParameter
{
public bool Equals(IParameter other)
{
if (other == null)
{
return false;
}
return other is NonRequestScopedParameter;
}
public object GetValue(IContext context, ITarget target)
{
throw new NotSupportedException("this parameter does not provide a value");
}
public string Name
{
get { return typeof(NonRequestScopedParameter).Name; }
}
// this is very important
public bool ShouldInherit
{
get { return true; }
}
}
[Fact]
public void FactMethodName()
{
var kernel = new StandardKernel();
// this is the default binding
kernel.Bind<IFakeDbContext>().To<RequestScopeDbContext>();
// this binding is _only_ used when the request contains a NonRequestScopedParameter
// in call scope means, that all objects built in the a single request get the same instance
kernel.Bind<IFakeDbContext>().To<CallScopeDbContext>()
.When(x => x.Parameters.OfType<NonRequestScopedParameter>().Any())
.InCallScope();
// let's try it out!
var task = kernel.Get<SomeTask>(new NonRequestScopedParameter());
// verify that the correct binding was used
task.FakeDbContext.Should().BeOfType<CallScopeDbContext>();
// verify that all children of the task get injected the same task instance
task.FakeDbContext.Should()
.Be(task.Dependency1.FakeDbContext)
.And.Be(task.Dependency2.FakeDbContext);
}
}
Since, as you say, the task scheduler does not make use of the IoC to create the task, it only supports a parameterless constructor. In that case you can make use DependencyResolver.Current (however, note that i'm in no way an expert on asp.net /MVC so i'm not making any claims that this is thread safe or working 100% reliably):
public class TaskExecutor : ITask
{
public TaskExecutor()
: this(DependencyResolver.Current.GetService<IResolutionRoot>())
{}
internal TaskExecutor(IResolutionRoot resolutionRoot)
{
this.resolutionRoot = resolutionRoot;
}
public void Execute()
{
IFooTask actualTask = this.resolution.Get<IFooTask>(new NonRequestScopedParameter());
actualTask.Execute();
}
}

Get/Set HttpContext Session Methods in BaseController vs Mocking HttpContextBase to create Get/Set methods

I created Get/Set HttpContext Session Methods in BaseController class and also Mocked HttpContextBase and created Get/Set methods.
Which is the best way to use it.
HomeController : BaseController
{
var value1 = GetDataFromSession("key1")
SetDataInSession("key2",(object)"key2Value");
Or
var value2 = SessionWrapper.GetFromSession("key3");
GetFromSession.SetDataInSession("key4",(object)"key4Value");
}
public class BaseController : Controller
{
public T GetDataFromSession<T>(string key)
{
return (T) HttpContext.Session[key];
}
public void SetDataInSession(string key, object value)
{
HttpContext.Session[key] = value;
}
}
Or
public class BaseController : Controller
{
public ISessionWrapper SessionWrapper { get; set; }
public BaseController()
{
SessionWrapper = new HttpContextSessionWrapper();
}
}
public interface ISessionWrapper
{
T GetFromSession<T>(string key);
void SetInSession(string key, object value);
}
public class HttpContextSessionWrapper : ISessionWrapper
{
public T GetFromSession<T>(string key)
{
return (T) HttpContext.Current.Session[key];
}
public void SetInSession(string key, object value)
{
HttpContext.Current.Session[key] = value;
}
}
The second one seems the best. Although I would probably write those two as extension methods to the HttpSessionStateBase instead of putting them into a base controller. Like this:
public static class SessionExtensions
{
public static T GetDataFromSession<T>(this HttpSessionStateBase session, string key)
{
return (T)session[key];
}
public static void SetDataInSession<T>(this HttpSessionStateBase session, string key, object value)
{
session[key] = value;
}
}
and then inside the controllers, or helpers, or something that has an instance of HttpSessionStateBase use it:
public ActionResult Index()
{
Session.SetDataInSession("key1", "value1");
string value = Session.GetDataFromSession<string>("key1");
...
}
Writing session wrappers is useless in ASP.NET MVC as the HttpSessionStateBase provided by the framework is already an abstract class which could be easily mocked in unit tests.
Just a little correction for the SetDataInSession method of the latest post. In my opinion, it´s a elegant solution! Thanks Darin Dimitrov.
public static class SessionExtensions
{
public static T GetDataFromSession<T>(this HttpSessionStateBase session, string key) {
return (T)session[key];
}
public static void SetDataInSession(this HttpSessionStateBase session, string key, object value) {
session[key] = value;
}
}
First create this class, and after remember to refer its namespace in the Controller class that will call this methods.
When getting the session value:
string value = Session.GetDataFromSession<string>("key1");
The must be a compatible type with the object persisted in the session.

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; }
}
}

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