I am using Caliburn.Micro in combination with Xamarin.Forms. Within my App class, I register an interface ILicenseInfo with a class LicenseInfoImplementation via the SimpleContainer's PerRequest method.
CM then injects an object when my view model is created (see ViewModelOne) which is what I want. However, I don't see how I can extend this to a collection of objects. Lets say I would like CM to instantiate ViewModelTwo which expects a collection of object. How would I have to change App.cs and the XAML of ViewModelTwo to make that happen?
public partial class App : FormsApplication
{
private readonly SimpleContainer _container;
public App (SimpleContainer container)
{
InitializeComponent();
this._container = container;
// register interface and class
_container.PerRequest<ILicenseInfo, LicenseInfoImplementation>();
//....
}
}
public ViewModelOne(ILicenseInfo license)
{
// Great, Caliburn.Micro injects an LicenseInfoImplementation object
}
public ViewModelTwo(IEnumerable<ILicenseInfo> licenses)
{
// No idea
}
I finally used the following pattern. Not the most elegant way to do it but the best I found ...
public ViewModelTwo() : base (IoC.GetAll<ILicenseInfo>())
{
}
public ViewModelTwo(IEnumerable<ILicenseInfo> licenses)
{
// Do something with licenses
}
Related
I'm using Unity.MVC for DI in my ASP.NET MVC 4.6 app. I have a service interface passed into the controller and that's working great. Now I want to pass in an interface to the EF context to the service but I'm not sure how to do this. I've read EF has this IObjectContextAdapter that I could pass into my service ctor and that works, but I need to then query the actual tables on inside my service from this context but because it's an IObjectContextAdapter it doesn't know my tables. How do I do this?
public class ContactService : IContactService
{
//private ContactsEntities context;
private IObjectContextAdapter context;
// test ctor
public ContactService(IObjectContextAdapter ctx)
{
context = ctx;
}
// prod ctor
public ContactService()
{
context = new ContactsEntities();
}
List<Contact> GetAllContacts()
{
return (from c in context.ObjectContext.?? // I need to query the Contacts table that would be attached to the actual context I pass in but still keep the decoupling from using an Interface passed into the ctor
}
}
The IObjectContextAdapter is the type of ObjectContext property of DbContext.
You should subclass DbContext e.g. ContactsDatabaseContext
public class ContactsDatabaseContext : DbContext, IContactsDatabaseContext
{
// ...
}
And then just register your ContactsDatabaseContext with your IoC container. Something like this:
container.RegisterType<IContactsDatabaseContext, ContactsDatabaseContext>();
Your ContactsDatabaseContext class and IContactsDatabaseContext interface should have properties of type DbSet<T> that refer to your tables e.g.:
IDbSet<BrandDb> Users { get; set; }
UPDATE:
Since you are using a generated file, then do this:
public partial class ContactsDatabaseContext : IContactsDatabaseContext
{
// Expose the DbSets you want to use in your services
}
In my application i configured structuremap like
public class DefaultRegistry : Registry {
#region Constructors and Destructors
public DefaultRegistry() {
Scan(
scan => {
scan.Assembly("Eterp.Data.ErpCore");
scan.Assembly("Eterp.Data.Seed");
scan.Assembly("Eterp.Application.ErpCore");
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
ForConcreteType<AclAuthorizationManager>().Configure.Ctor<IResourceOperationAppService>()
}
#endregion
}
And i have class
public class AclAuthorizationManager : ClaimsAuthorizationManager
{
private readonly IResourceOperationAppService _resourceOperationAppService;
public AclAuthorizationManager(IResourceOperationAppService resourceOperationAppService)
{
_resourceOperationAppService = resourceOperationAppService;
}
public override bool CheckAccess(AuthorizationContext context)
{
var isCurrentUserAuthorized = context.Principal.Identity.IsAuthenticated;
return isCurrentUserAuthorized && _resourceOperationAppService.CanAccessResource(context.Action.FirstOrDefault().Value, context.Principal.Claims);
}
}
This class is custom claim authorization class using in my application, but when i exceuting the application,i am getting an error which related to lack of parameter required by the constructor, ( This class has constructor with parameter type IResourceOperation). but i already configured all the details in structureMap . i am sure that my structuremap configuration is working 100% well expect the creation of this AclAuthorizationManager class.because i am able to to apply DI in other classes.
What is wrong part in my code?
in my experience when you specify the type constructor must say that inherits from the interface.
Therefore, you should replace this line:
ForConcreteType<AclAuthorizationManager>().Configure.Ctor<IResourceOperationAppService>()
By:
ForConcreteType<AclAuthorizationManager>().Configure.Ctor<IResourceOperationAppService>().Is<ResourceOperationAppService>()
Where is the implementation ResourceOperationAppService IResourceOperationAppService.
This is my first try using DI, I've chosen ninject for it's reportedly easy learning curve, and have this question.
I'm creating objects like this:
var registrants = JsonConvert.DeserializeObject<List<Registrant>>(input);
I currently have this constructor for Registrant
[Inject]
public Registrant(IMemberRepository memberRepository)
{
_memberRepository = memberRepository;
}
What is the best way to have the repository dependency be injected into the deserialized object(s) using Ninject?
You can't use constructor injection with objects that are not created by Ninject (e.g. deserialized objects). But you can use property injection. Just call kernel.Inject(obj)
One question that remains is why you want to inject those objects. Normally, you don't want to use depedency injection on data container objects. In a proper design they don't have any dependency on services. The operations that need to be done on the services are done by the owner of the data container objects. I recommend to consider a refactoring of your design.
Assuming you're using Ninject V2, and you're using it in the context of an ASP.NET app, you should be using Ninject.Web to do the hookups.
Then you set up a Global class with the Factory Method support hooked in:
public class Global : NinjectHttpApplication
{
protected override Ninject.IKernel CreateKernel()
{
var kernel = new StandardKernel( new Module() );
kernel.Components.Add( new FuncModule( ) );
return kernel;
}
}
that registers the module that will Bind IMemberRepository to something:
public class Module : NinjectModule
{
public override void Load()
{
Bind<IMemberRepository>().To<MemberRepository>();
}
}
and the page wires up like this:
public class ThePage : PageBase
{
readonly Func<Registrant> _createRegistrant;
public ThePage( Func<Registrant> createRegistrant )
{
_createRegistrant = createRegistrant;
}
private void OnCreateRegistrant()
{
var newRegistrant = _createRegistrant();
}
}
NB not 100% sure if constructor injection is supported for Web Forms pages or wheter the above needs to drop to property injection... anyone?
(assuming the classes you have are as follows:)
public class MemberRepository : IMemberRepository
{
}
public interface IMemberRepository
{
}
public class Registrant
{
private readonly IMemberRepository _memberRepository;
public Registrant( IMemberRepository memberRepository )
{
_memberRepository = memberRepository;
}
}
I'm trying to add logging with aspect orientated programming using castle windsor in plain asp.net, i.e. not MVC
I've added a class that implements the IInterceptor interface and an attribute that inherits from Attribute.
public class LogAttribute : Attribute
{
public Level LogLevel { get; set; }
public LogAttribute(Level level)
{
LogLevel = level;
}
}
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
MethodInfo mi = invocation.Method;
LogAttribute[] atts = (LogAttribute[])mi.GetCustomAttributes(typeof(LogAttribute), true);
// if method not marked with InternalUseRestricted attribute, then pass on call
if (atts.Length == 0)
{
invocation.Proceed();
}
else
{
ISeiLogger log = LoggerFactory.GetLogger(mi.DeclaringType.ToString());
//assume only one logging attribute
//log on entry
log.LogEnter(atts[0].LogLevel);
//allow code to continue
invocation.Proceed();
//log on exit
log.LogExit(atts[0].LogLevel);
}
}
}
Now in the global.asax.cs I've added the following:
public partial class Global : System.Web.HttpApplication, IoCProvider
{
private void InitializeIoC()
{
container = new WindsorContainer();
container.Install(new Sei.Aspect.AspectInstaller());
}
public IWindsorContainer Container
{
get { return container; }
}
private static Sei.Logging.ISeiLogger log;
private IWindsorContainer container;
public override void Init()
{
base.Init();
InitializeIoC();
}
and I've created an installer class:
public class AspectInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
//container.Register(AllTypes.FromAssembly(Assembly.GetExecutingAssembly()).BasedOn<IInterceptor>().Configure(component => component.LifeStyle.PerWebRequest));
container.Register(Component.For<IInterceptor>().ImplementedBy<LoggingInterceptor>().LifeStyle.PerWebRequest);
container.Register(Component.For<IInterceptor>().ImplementedBy<InternalUseRestrictedInterceptor>().LifeStyle.PerWebRequest);
container.Register(Component.For<IInterceptor>().ImplementedBy<CachingInterceptor>().LifeStyle.PerWebRequest);
}
}
I now want to add the attribute to some arbitary page's code behind class and some arbitary virtual method, as in
[Log(Level.Info)]
protected string Login(string username, string password)
{
DoSomething();
}
This obviously doesn't work. Do I need to change the way I'm instantiating the page (its a page's code-behind class) to use a container? Or is it the way I'm registering the interceptors? I want to be able to use the interceptors on any class going forward and not have to tell the container about each and every class that I have in my application.
Short answer: it's not possible.
Long answer: due to the way ASP.NET Web Forms works, it doesn't let anyone interfere with the page instantiation. Some claim that using a custom PageHandlerFactory lets you do IoC, but this only lets you set properties after the page has been instantiated, which is simply not enough for proxying.
So runtime proxy libraries such as DynamicProxy or LinFu can't do anything about this. But you may be able to use compile-time aspect weavers, such as PostSharp.
Alternatively, make your code-behind as slim as possible, deferring actual logic to Windsor-managed components.
I see tons of material on how to inject services using the ControllerBuilder.Current.SetControllerFactory but what if I wanted to resolve my services in the model? Would I have to get them from the Controller layer and pass them up?
Ideally you should not be injecting services into the model as this would require you to register your model with the container.
If you need to use a service within a model instance, pass the service in as a method argument and then you can inject the service into the controller.
Without knowing more about the scenario it is hard to give clearer advice, however the following outline may help:
public interface IService
{
// ... describe the contract the service must fulfill
}
public class Model
{
public void DoSomething( IService service )
{
// ... do the necessary work using the service ...
}
}
public class AController : Controller
{
private readonly IService _injectedService;
public AController( IService injectedService )
{
_injectedService = injectedService;
}
public ActionResult SomeAction( int modelId )
{
// ... get the model from persistent store
model.DoSomething( _injectedService );
// ... return a view etc
}
}