can castle resolve cross dependent properties? - c#

i have a situation silmilar as following
public class FooService : IFooService
{
public IBarService BarService { get; set; }
}
public class BarService : IBarService
{
public IFooService FooService { get; set; }
}
IFooService and IBarService both are inherited from IApplicationService
Component registrar looks like this
container.Register(
AllTypes.FromAssemblyContaining<IApplicationService>()
.BasedOn<IApplicationService>()
.WithService.FromInterface()
.LifestyleSingleton());
The problem is that properties are null. If i add any other service that doesnt use foo or bar service, the service is resolved correctlty.
It looks like castle windsor cant handle cross references. Or is there something i should add into component registrar?

I tried constructor injection and seems it is working.

Related

Nested Interface (empty) Dependency Registration

I have a parent interface that is empty, and its only purpose is to implement 2 other child interfaces. This way I can reduce the number of constructor parameters to an acceptable count. The problem is I dont know how to register this dependency in the container since there is no implementation of the parent Interface. Entries are present for the child services, but the dependent services are unable to find the required service dependencies for both children at this point.
services.AddScoped<IServiceChild1, IServiceChild1>();
services.AddScoped<IServiceChild2, IServiceChild2>();
// how to register IServiceParent
public interface IServiceParent: IServiceChild1, IServiceChild2
{
}
Make it a class instead:
public class ServiceParentServices
{
public IServiceChild1 Service1 { get; }
public IServiceChild2 Service2 { get; }
public class ServiceParentServices(IServiceChild1 service1, IServiceChild2 service2)
{
Service1 = service1;
Service2 = service2;
}
}
Register this class to the ServiceCollection, and when you want to consume it, just inject ServiceParentServices into the constructor
public class ServiceParent
{
private ServiceParentServices _services;
public ServiceParent(ServiceParentServices services)
{
_services = services;
}
}
As an alternative you could also inject IServiceProvider, but this more like the ServiceLocator anti pattern.

ServiceStack IAppSettings was not ready and would result NULL reference exception if used in constructor

It seems like the IAppSettings implementation was not ready from IoC in the constructor.
Before I go into details, I've read similar problems:
ServiceStack doesn't auto-wire and register AppSettings
Instantiation of POCO objects with ServiceStack's IAppSettings is not working
Both were answered by #mythz that he was not able to reproduce it.
From the Doc
"ServiceStack made AppSettings a first-class property, which defaults to looking at .NET's App/Web.config's.": https://docs.servicestack.net/appsettings#first-class-appsettings
And there is default IoC registration already in Funq to give you AppSettings when you ask for IAppSettings:
What I have
All my codes are in the repo: https://github.com/davidliang2008/MvcWithServiceStack
The demo app is just an ASP.NET MVC app (.NET 4.8) that built using the template, the simplest you can get, with ServiceStack (5.12.0) installed:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
new AppHost().Init();
}
}
public class AppHost : AppHostBase
{
public AppHost() : base("MvcWithServiceStack", typeof(ServiceBase).Assembly) { }
public override void Configure(Container container)
{
SetConfig(new HostConfig
{
HandlerFactoryPath = "api";
}
ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory(container));
}
}
Then I have a base class for the ServiceStack Service, and a HelloService just to demo:
public abstract class ServiceBase : Service { }
public class HelloService : ServiceBase
{
public IAppSettings AppSettings { get; set; }
public object Get(HelloRequest request)
{
return new HelloResponse
{
Result = $"Hello, { request.Name }! Your custom value is { AppSettings.Get<string>("custom") }."
};
}
}
[Route("/hello/{name}")]
public class HelloRequest : IReturn<HelloResponse>
{
public string Name { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
What works
When you're not using IAppSettings in the constructor, whether in the HelloService or its base class ServiceBase, everything works out fine.
When you clone the project to your local, if you navigate to /api/hello/{your-name}, you will see its response would be able to get the custom value from web.config:
What doesn't work
When you're trying to get the IAppSettings and initialize something else with some app setting values in the constructor - whether it's in the child class or the base class, IAppSettings will fail to get the implementation from IoC, and result a NULL reference exception:
public abstract class ServiceBase : Service
{
public IAppSettings AppSettings { get; set; }
public ServiceBase()
{
// AppSettings would be NULL
var test = AppSettings.Get<string>("custom");
}
}
OR
public class HelloService : ServiceBase
{
public HelloService()
{
// AppSettings would be NULL
var test = AppSettings.Get<string>("custom");
}
}
You cannot use any property dependency in the constructor since the properties can only be injected after the class is created and the constructor is run.
You'll only be able to access it in the Constructor by using constructor injection, e.g:
public class HelloService : ServiceBase
{
public HelloService(IAppSettings appSettings)
{
var test = appSettings.Get<string>("custom");
}
}
Or accessing the dependency via the singleton:
public class HelloService : ServiceBase
{
public HelloService()
{
var test = HostContext.AppSettings.Get<string>("custom");
}
}

Derived Class How to inject ?

ASP.Net Core Web API
Does the parent class have no empty constructor
derived class Autofac injection ?
If the injection class is added after the parameter, it cannot be used
public class A
{
public A(string e1,string e2){}
}
public class B:A
{
private readonly IProductService _productService;
public B(IProductService productService):base(string e1,string e2)
{
_productService = productService
}
public void test()
{
_productService.AddProduct("");
}
}
AutoFac has no problem configuring
_productService exception occurred
You should try it like this:
public B(IProductService productService, string e1,string e2):base(e1,e2)
{
_productService = productService
}
And then configure Autofac like this for this class registration:
builder.Register(c => new B(c.Resolve<IProductService>(), "e1_val","e2_val"));
If the B class will implement an interface at some point you can use it like this also:
builder.RegisterType<B>().As<IB>()
.WithParameter("e1", "e1value")
.WithParameter("e2", "e2value");
Keep in mind that you have a lot of flexibility with Autofac, please check their documentation at: Autofac Parameters Register for even more information.

Using ServiceStack Funq IoC: how dependencies are injected?

I have WinForm application and I want to use ServiceStack dependency injection mechanism:
public class AppHost : AppHostBase
{
public AppHost()
: base("MyName", typeof(AppHost).Assembly)
{
}
public override void Configure(Container container)
{
container.RegisterAutoWiredAs<AppApplicationContext, IAppApplicationContext>();
}
}
Then in some form class use it:
public class SomeClass : AppBaseForm
{
public IAppApplicationContext AppApplicationContext { get; set; }
public SomeClass(IAppApplicationContext appApplicationContext)
{
AppApplicationContext = appApplicationContext;
}
public SomeClass()
{
}
}
But AppApplicationContext is always null. When in parameterless constructor I write:
AppApplicationContext = AppHostBase.Resolve<IAppApplicationContext>();
then every thing is OK. But is this right way to do that? I mean AppApplicationContext should not be resolved by IoC automatically? And WinForm must have parameterless constructor.
Rest of code:
private static void Main()
{
var appHost = new AppHost();
appHost.Init();
}
public interface IAppApplicationContext
{
}
public class AppApplicationContext : IAppApplicationContext
{
}
You need to call AutoWire to have the container inject the dependancies. You can use it in your WinForm app like this:
public class SomeClass : AppBaseForm
{
public IAppApplicationContext AppApplicationContext { get; set; }
public SomeClass()
{
// Tell the container to inject dependancies
HostContext.Container.AutoWire(this);
}
}
When you use a regular ServiceStack service, the AutoWire happens behind the scenes during the request pipeline when ServiceStack creates an instances of your Service.
I have created a fully working example here. Note: The demo is just a console application, not WinForms but it does shows the IoC being used outside of the ServiceStack service, and it works no differently.

How to debug when a dependency fails to instantiate?

How do you debug dependency injection (using Unity DI) when the dependancy does not instantiate?
eg Given a service class with dependencies:
public class FooService : IFooService
{
[Dependency]
public BarService BarService { get; set; }
[Dependency]
public AnotherService AnotherService { get; set; }
// other code fails because BarService and AnotherService are null
}
And in Global.asax.cs
private void ConfigureIoC()
{
container
.ConfigureAutoRegistration()
.LoadAssembliesFrom(assemblyPaths)
.ExcludeSystemAssemblies()
.Include(If.Any, Then.Register())
.ApplyAutoRegistration();
var serviceLocator = new UnityServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => serviceLocator);
}
The IFooService is also instantiated by Unity, but that uses constructor injection instead (and it works):
public class FooController : Controller
{
private readonly IFooService _fooService;
public FooController(IFooService fooService)
{
_fooService = fooService;
}
}
How can I debug this to see why the dependencies are failing to instantiate. No exceptions are being thrown (or if they are then Elmah is not catching and logging them).
The dependency is not injected because the DependencyAttribute is on the concrete class instead of the interface.
As DI attributes can be harmful I would recommend you change the registration to
container.RegisterType<IFooService,FooService>(new InjectionProperty("BarService"), new InjectionProperty("AnotherService"));
Resolving IFooService will then return an instance of FooService with the injected dependencies.
Call container.Resolve<IFooService>();
Where/how is resolution of IFooService happening?

Categories