Autofac register generic with multiple paramters? - dependency-injection

Here are the classes and interfaces I'm dealing with.
public interface IAccountService
{
//omitted for brevity...
}
public abstract class UserClientBase<T> : ClientBase<T> where T : class
{
protected UserClientBase(Binding binding, EndpointAddress remoteAddress, string userName, string password)
: base(binding, remoteAddress)
{
if (ClientCredentials == null) return;
ClientCredentials.UserName.UserName = userName;
ClientCredentials.UserName.Password = password;
}
}
public class AccountProxy : UserClientBase<IAccountService>, IAccountService
{
private static readonly WSHttpBinding Binding = WcfHelpers.ConfigureWsHttpBinding();
private static readonly EndpointAddress EndpointAddress =
new EndpointAddress(#"https://server.project.local/Project/Account/AccountService.svc");
public AccountProxy(string userName, string password)
: base(Binding, EndpointAddress, userName, password)
{
}
//omitted for brevity
}
public interface ISafeClient<out TService> : IDisposable where TService : class
{
//omitted for brevity...
}
public class SafeClient<TClient, TService> : ISafeClient<TService>
where TClient : UserClientBase<TService>, TService
where TService : class
{
//omitted for brevity...
}
public AccountController(ISafeClient<IAccountService> accountProxy)
{
_accountProxy = accountProxy;
}
I'm using Asp.net MVC 5 with Autofac integration, here are the registrations in my Global.asax Application_Start method.
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<AccountProxy>().As<IAccountService>().InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(SafeClient<,>)).As(typeof(ISafeClient<>)).InstancePerLifetimeScope();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
Now when I try to browse to a page handled by the AccountController, I get the following exception in the URL.
None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'MyMvcApp.Controllers.AccountController' can be invoked with the
available services and parameters: Cannot resolve parameter
'Project.Client.Proxies.ISafeClient`1[Project.Client.Contracts.Service.IAccountService]
accountProxy' of constructor 'Void
I'm not sure what I'm missing here. When I look in the container's ComponentRegistry at runtime I see the Controllers and the AccountProxy. Thanks in advance.
Update:
I can inject an IAccountService successfully if I register it like this instead:
builder.Register(a => new AccountProxy("userName", "password")).As<IAccountService>();
However when I try to inject the ISafeClient I still get an exception. I think I have a larger problem here. Essentially, I'm trying to wrap a ClientBase to include safe disposing and retry logic. It handles communication and message exceptions, faulted channel states, etc. Every time I execute a method on my SafeClient, the ClientBase is re-instantiated, then automatically disposed of. If this is the case, should I even be injecting it? Ugghh.. I'm confused.
Update 2:
Looks like I can just register like this.
builder.RegisterType<SafeClient<AccountProxy, IAccountService>>().As<ISafeClient<IAccountService>>().InstancePerLifetimeScope();
Then my AccountController changes to this:
private readonly ISafeClient<IAccountService> _accountProxy;
public AccountController(ISafeClient<IAccountService> accountProxy)
{
_accountProxy = accountProxy;
}
Is there any downside to doing it this way, other than the obvious which is having to register teach safe client individually?

Related

Configure Unity container per-request in OWIN middleware

I'm wanting to configure registrations in a Unity container being used by ASP.NET Web API 2 based on properties of a HTTP request. For example, a request to /api/database1/values should result in a Unity container configuration with an IDbContext configured for database1, while a request to /api/database4/values will get an IDbContext configured for database4.
I've gotten so far as using UnityHierarchicalDependencyResolver as the dependency resolver, so types registered with HierarchicalLifetimeManager last only for the lifetime of the request. This works well for getting types resolved per request. But how to get them registered per request using OWIN middleware is beyond me.
In my middleware, a call to System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUnityContainer)) gets an instance of IUnityContainer, but it's the same container for all requests, including any registrations from previous requests.
By encapsulating UnityHierarchicalDependencyResolver with my own implementation of IDependencyResolver I can see that IDependencyResolver.BeginScope isn't called until much later in the process. So the problem would seem to be that the child container isn't created until Web API wakes up, long after my middleware calls Next(..).
Is there a way I can get the scope of my dependency resolver to start sooner? Is there some other strategy that I'm missing. In case it makes any difference, I'm hosting in IIS, but favouring the OWIN middleware approach.
Update
This isn't an answer, and it's too big for a comment, but after struggling to solve this with Unity I decided to switch to Autofac and it all just fell into place.
The Autofac OWIN packages (Autofac.Mvc5.Owin, Autofac.Owin, Autofac.WebApi2.Owin) make it dead easy to use Autofac within the OWIN pipeline and ensure appropriate lifetime management in ASP.NET MVC and Web API. This was the missing link.
I couldn't find a way to reconfigure the container per-request, but it did at least make it possible to configure a factory per-request (so yes, #Haukinger and #alltej, you were right to push in that direction.
So I register a factory like:
builder.RegisterType<DataDependencyFactory>().InstancePerRequest();
And register the create method of that factory like:
builder
.Register(c => c.Resolve<DataDependencyFactory>().CreateDataDependency())
.As<IDataDependency>()
.InstancePerRequest();
Registering the factory this way is particularly useful, because downstream dependents don't need to be aware of the factory. I like this because my dependents don't need a factory, they need an instance. The container bends to the needs of my dependents, not the other way around :)
Then, in a piece of OWIN middleware, I resolve the factory, and set a property on it according to the properties of the request. Subsequent resolution of IDataDependency in an MVC or Web API controller, or anything else later in the OWIN pipeline, will get an instance configured according to the property on the factory.
Based on your api URL ("/api/database4/values"), I suggest that you create a filter attribute(e.g. DbIdFilter) so that you can reuse the filter attribute to other controller methods that follow similar url path/segment like this below:
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/values")]
public IHttpActionResult GetValues()
{
return Ok();
}
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/products")]
public IHttpActionResult GetProducts()
{
return Ok();
}
First, create the filter attribute:
public class DbIdFilterAttribute : ActionFilterAttribute
{
private readonly string _routeDataId;
private const string defaultRouteName = "databaseId";
public DbIdFilterAttribute():this(defaultRouteName)
{}
public DbIdFilterAttribute(string routeDataId)
{
_routeDataId = routeDataId;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
var routeData = actionContext.Request.GetRouteData();
var dbId = routeData.Values[_routeDataId] as string;
//here we create the db instance at the filter level.
DbInstanceFactory.RegisterDbInstance(dbId);
}
}
Next, create an instance factory that will register/resolve the db instance during runtime:
public class DbInstanceFactory : IDbInstanceFactory
{
public static IDbInstance RegisterDbInstance(string databaseId)
{
var factory = UnityConfig.GetConfiguredContainer().Resolve<IDbInstanceFactory>();
return factory.CreateInstance(databaseId);
}
public IDbInstance CreateInstance(string databaseId)
{
var container = UnityConfig.GetConfiguredContainer();
//container.RegisterType<IDbInstance, DbInstance>();
container.RegisterType<IDbInstance, DbInstance>(new InjectionConstructor(databaseId));
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
public IDbInstance GetInstance()
{
var container = UnityConfig.GetConfiguredContainer();
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
}
public interface IDbInstanceFactory
{
IDbInstance CreateInstance(string databaseId);
IDbInstance GetInstance();
}
Register this factory class in UnityConfig.cs (or wherever you currently register the types):
container.RegisterType<IDbInstanceFactory, DbInstanceFactory>
(new ContainerControlledLifetimeManager());
It's registered ContainerControlledLifetimeManager since this factory does not have to be a per request.
So just a basic DbInstance class below(for clarity) that takes a parameter in the constructor (this parameter can be your connection string or a named connection):
public class DbInstance : IDbInstance
{
public string DbId { get; }
public DbInstance(string databaseId)
{
DbId = databaseId;
}
}
public interface IDbInstance
{
string DbId { get; }
}
In controller class, you can use it like this:
....
private IDbInstanceFactory _dbFactory;
public MyController(IDbInstanceFactory dbFactory)
{
_dbFactory = dbFactory;
}
// Alternate, if you want to use property injection instead of constructor injection
//[Dependency]
//public IDbInstanceFactory DbFactory { get; set; }
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/test")]
public IHttpActionResult Test()
{
var db = _dbFactory.GetInstance();
return Ok(db.DbId);
}
...

AddTransient service using info from request

I've got an app in asp.net core using the built-in DI framework. I'd like to add a per-request (i.e. transient) service to the provider, but I'd like to actually make use of the request in its construction.
services.AddTransient<IMyService>(provider => { ... });
That's the closest overload I can find, but the provider object doesn't have anything about the current request. Is there a way to achieve what I'm trying to do, without upgrading to a more robust DI framework?
As posted in the comments, you can inject the IHttpContextAccessor into your services and access it, if the HttpContext is the only thing you need.
public class MyService : IMyService
{
private readonly HttpContext context;
public MyService(IHttpContextAccessor httpContextAccessor)
{
if(IHttpContextAccessor==null)
throw new ArgumentNullException(nameof(httpContextAccessor));
context = httpContextAccessor.HttpContext;
}
}
However, if you need something that's only available in the controller or outside of HttpContext, you can create a factory and pass the parameters to the factory
public class MyServiceFactory : IMyServiceFactory
{
// injecting the HttpContext for request wide service resolution
public MyServiceFactory(IHttpContextAccessor httpContextAccessor) { ... }
public IMyService Create(IDependency1 dep1, IDependency2 dep 2, string someRuntimeConfig)
{
IServiceProvider provider = this.context.RequestServices;
var myService = new MyService(provider.GetService<ISomeRepository>(), dep1, dep2, someRuntimeConfig);
return myService;
}
}
and then inject the IMyServiceFactory to your classes where you'd need IMyService.

Cannot get a working Unity Session Lifetime Manager, ASP.NET MVC5

I've read and Googled everything on this, but can't seem to get it to work. I created a custom LifetimeManager for Unity in my MVC5 application based on these posts:
MVC3 Unity Framework and Per Session Lifetime Manager
This may be the issue I am experiencing
Here is my SessionLifetimeManager
public class SessionLifetimeManager : LifetimeManager
{
private string key = Guid.NewGuid().ToString();
public override object GetValue()
{
return HttpContext.Current.Session[key];
}
public override void RemoveValue()
{
HttpContext.Current.Session.Remove(key);
}
public override void SetValue(object newValue)
{
HttpContext.Current.Session[key] = newValue;
}
}
I only have a few types I'm playing with, here is the relevant registrations in UnityConfig.cs:
container.RegisterType<IEpiSession, EpiSession>(new SessionLifetimeManager(),
new InjectionConstructor(config.AppServerURI, config.PathToSysConfig));
container.RegisterType<IReportRepository, EpicorReportRepository>(new TransientLifetimeManager());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Note that the EpicorReportRepository has a dependency on IEpiSession via constructor injection.
public class EpicorReportRepository : IReportRepository
{
private IEpiSession session;
// DI constructor
public EpicorReportRepository(IEpiSession session) {
this.session = session;
}
// ...
}
My Problem: After the first user / session connects to the application, every new user / session after that seems to still be using the EpiSession object and credentials that the first user had create/injected for him. This seems to be a common pattern used on the interwebs, so I'm wondering what I am missing.
How did you test that IEpiSession is the same in different Sessions?
Try to open you application from different browsers. If you open several tabs in the same browser then the same session is used.
I checked your code and it works for me.
There is the only one difference in SetResolver():
DependencyResolver.SetResolver(
type => container.Resolve(type),
types => container.ResolveAll(types));
The full registration code is the following:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
var container = new UnityContainer();
container.RegisterType<IEpiSession, EpiSession>(
new SessionLifetimeManager(),
new InjectionConstructor("config.AppServerURI", "config.PathToSysConfig"));
container.RegisterType<IReportRepository, EpicorReportRepository>(new TransientLifetimeManager());
DependencyResolver.SetResolver(
type => container.Resolve(type),
types => container.ResolveAll(types));
}
}

How MeController constractor calls?

When I create default SPA template progect VS2013 creates MeController. Calling Get I have a user information. But when I create almost the same Controller, for example UserController, and copy-paste all from Me to User I do not have necessary info about user on breakpoint in the method:
// GET api/Me
public GetViewModel Get()
{
var user = UserManager.FindById(User.Identity.GetUserId());
return new GetViewModel() { Hometown = user.Hometown };
}
I don't uderstand this magic! I also do not see a caller of constractor and sender of userManager. Where is it?
public MeController(ApplicationUserManager userManager)
{
UserManager = userManager;
}
There is a default constructor in the MeController which gets called by default. In this case the UserManager, is got from the Owin contect as below
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
Even if you copy this over to a new class like UserController, this should happen. Are you using any DI library like StrucuteMap/Unity etc? Certain DI controllers choose the 'greediest' constructor(the one with the maximum arguments). You could override that by using appropriate methods for that DI library(like this if you are using StructureMap)
In case you would want to use your own UserManager you could use your own implementation of UserManager and have it used. But if you are planning to stick with the default, this is already added in Startup.Auth.cs into the Owin pipeline.

Dependency on a service layer with Ninject and MVC

I've got a problem with a bog standard three tier project using MVC that I'm trying to use Ninject with. I've got a MemberRepository:
public class MemberRepository : IMemberRepository{
public bool Save(Member member){
//saves member
}
}
I then have my Service Layer:
public class MemberService : IMemberService{
public bool Register(string email){
//Do Stuff & Populate Member Object
_repo.Save(member);
}
}
Given I'll be using Ninject what is the best way of me setting up my AccountController. Should I pass in the MemberService to the constructor like so:
public class AccountController : Controller
{
IMemberService _memberService;
public AccountController(IMemberService memberService)
{
_memberService = memberService;
}
}
Or pass in the repository:
public class AccountController : Controller
{
IMemberService _memberService;
public AccountController(IMemberRepository memberRepo)
{
_memberService = new MemberService(memberRepo);
}
}
Or Both?
I originally had just a repository (no service layer) but I've had to implement a service layer and I'm not sure how I'd handle the 'dependency' when registering the kernal in my NinjectWebCommon.cs file. Which was originally just this:
kernel.Bind<IMemberRepository>().To<SqlMemberRepository>();
But now I'm wondering if I need to register the IMemberService and have the repo as some kind of parameter.
:s Feeling kind of lost. Hope I'm making sense and someone can help out.
I've never used Ninject, I've been using Unity, but the same principles exist so hopefully this might help.
The service layer is the thing that is exposed to the controller - the controller needs to know nothing about the underlying repository. The flow is as follows, and each layer doesn't know about the layers above it:
Controller -> Service > Repository
So I would go with option 1, and then inject the repository into the constructor of the service.
public class MemberService : IMemberService {
private readonly IMemberRepository _repo;
[Inject]
public MemberService (IMemberRepository repo){
this._repo = repo;
}
public bool Register(string email){
//Do Stuff & Populate Member Object
_repo.Save(member);
}
}
and
public class AccountController : Controller
{
private readonly IMemberService _memberService;
[Inject]
public AccountController(IMemberService memberService)
{
_memberService = memberService;
}
}
That example obviously uses constructor injection but you can use property/field injection if you want instead. When you register your dependencies, you'll have to register both:
kernel.Bind<IMemberRepository>().To<SqlMemberRepository>();
kernel.Bind<IMemberService>().To<MemberService>();

Resources