In another stackoverflow question MVC5 IoC and Authentication the first answer states the author uses Dependency Injection to inject the IPrincipal. I would love to do this for my assemblers so that I don't have to pass the current user (IPrincipal) from the controller.
Can anyone give an example of how to use DI to inject the IPrincipal in C# MVC5? Below is the IoC I first want to implement it in. Added after first answer given.
public class ViewModelAssemblersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IAspNetUserAssembler>()
.ImplementedBy<AspNetUserAssembler>());
}
}
For Castle Windsor, it's something like:
container.Register(Component.For<IPrincipal>()
.LifeStyle.PerWebRequest
.UsingFactoryMethod(() => HttpContext.Current.User));
Its going to be dependent on your IoC container... for me, I use Unity, and in my container registration I'm able to do the following:
container.RegisterType<IPrincipal>(new InjectionFactory(u => HttpContext.Current.User));
Using the InjectionFactory, unity will execute the lambda to return the current HttpContext.Current.User at the time of constructor injection. I'm also able to use the same type of registration in my non web applications, instead referencing the Thread.CurrentPrincipal.
Related
Currently I am using DI in azure functions the standard way
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
/*Register dependencies*/
}
}
(Microsoft.Azure.Functions.Extensions.DependencyInjection.FunctionsStartup)
Is it possible to switch to https://github.com/dadhi/DryIoc container while still being able to use DI to resolve dependencies through constructor of azure functions? If so, how?
So the answer to my question is that it is possible. But it requires implementing custom IJobActivatorEx and IJobActivator. And then replace it in IServiceCollection.
hostBuilder.Services.Replace( ServiceDescriptor.Singleton(typeof(IJobActivator), typeof(ScopedJobActivator)));
hostBuilder.Services.Replace( ServiceDescriptor.Singleton(typeof(IJobActivatorEx), typeof(ScopedJobActivator)));
I found this implementation in Autofac container extension https://github.com/junalmeida/autofac-azurefunctions in class ConfigurationExtensions
Sadly, I don't yet have working implementation for DryIoc.
Ok, here is the implementation in DryIoc https://github.com/dadhi/DryIoc/blob/master/src/DryIoc.AzureFunctions/DryIocAzureFunctions.cs
There is a preview package as well: https://www.nuget.org/packages/DryIoc.AzureFunctions/1.0.0-preview-01
Having soured books, I can't figure out what in a C# MVC project I'm taking over causes the Controller constructors to always be passed a repository argument.
public partial class AdminController : ApiController
{
IDataRepository _repo;
public AdminController(IDataRepository repo)
{
_repo = repo;
}
}
Even other classes who are NOT partials are written this way.
I have looked at the class (or Interface) that these inherit from.
Any ideas?
Thanks in advance.
This is called dependency injection.
Asp.net core has a built-in DI container. But for old Asp.net projects, you should add a library to use this. I don't know which library you use, but I can give some common examples:
Simple Injector
https://simpleinjector.readthedocs.io/en/latest/aspnetintegration.html
// You'll need to include the following namespaces
using System.Web.Mvc;
using SimpleInjector;
using SimpleInjector.Integration.Web;
using SimpleInjector.Integration.Web.Mvc;
// This is the Application_Start event from the Global.asax file.
protected void Application_Start(object sender, EventArgs e) {
// Create the container as usual.
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
// Register your types, for instance:
container.Register<IUserRepository, SqlUserRepository>(Lifestyle.Scoped);
// This is an extension method from the integration package.
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
Castle Windsor
https://gist.github.com/martinnormark/3128275
public class ControllersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(AllTypes.FromThisAssembly()
.Pick().If(t => t.Name.EndsWith("Controller"))
.Configure(configurer => configurer.Named(configurer.Implementation.Name))
.LifestylePerWebRequest());
}
}
Asp.net Core
https://learn.microsoft.com/tr-tr/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddScoped<IMyDependency, MyDependency>();
}
Like others have said, dependency injection. But some more details:
.net framework and .net core handle it differently.
It's not built in at all in the .net framework. You'll want to check you global.asax file to figure out whats going on. Most of the time its done through a nuget package. there are many popular ones like autofaq, ninject, simple injector etc. You should see some stuff about building a container and registering services.
.net core has its own dependency injection framework it ships with, so quite often that's used. Although sometimes people still use a nuget package for something more complex. The .net core stuff will be in the Startup.cs file. See if theres anything like services.AddTransient anywhere.
It's possible, though unlikely someone wrote there own dependency injection framework in your project. In that case you'd be looking for them to have written a ControllerFactory implementation.
If you can't figure it out from here, please add either the global.asax file, or the startup.cs file to your question.
This is Dependency Injection, have a look in startup for something like
services.AddTransiant<IDataRepository, DataRepo>();
This tells the dependency injection container to instantiate IDataRepository with an instance of DataRepo.
I have problem with Simple Injector in my Web Api project. I user default AccountController generated by VS.
public AccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
In my configuration file I register:
var container = new Container();
// This is an extension method from the integration package.
container.RegisterWebApiFilterProvider(config);
container.RegisterWebApiControllers(config);
container.Register<IInitializeService, InitializeService>();
container.Register<IFolderRepository, FolderRepository>();
container.Register<IUserRepository, UserRepository>();
container.Register<ILogger, Logger>();
//Authentication Wrap
container.Register<IUserStore<User, Guid>, ApplicationUserStore>();
container.Register<IDataSerializer<AuthenticationTicket>, TicketSerializer>();
container.Register<ISecureDataFormat<AuthenticationTicket>,
SecureDataFormat<AuthenticationTicket>>();
container.Register<IDataProtector>(
() => new DpapiDataProtectionProvider().Create("ASP.NET Identity"));
container.Verify();
// 4. Register the container as MVC3 IDependencyResolver.
DependencyResolver.SetResolver(new SimpleInjectorWebApiDependencyResolver(container));
config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
I though that Simple Injector will be smart enough to handle all build in dependences responsible for default identity and i wont need to register them manually, but I'm getting exceptions if I wont register them.
Still getting an exception:
The constructor of type SecureDataFormat contains the parameter of type ITextEncoder with name 'encoder' that is not registered. Please ensure ITextEncoder is registered in the container, or change the constructor of SecureDataFormat.
Is there any way to handle that automatically?
I implemented a Web Api and I wrote this code.
This works for me
container.RegisterWebApiRequest<ISecureDataFormat<AuthenticationTicket>, SecureDataFormat<AuthenticationTicket>>();
container.RegisterWebApiRequest<ITextEncoder, Base64UrlTextEncoder>();
container.RegisterWebApiRequest<IDataSerializer<AuthenticationTicket>, TicketSerializer>();
container.RegisterWebApiRequest<IDataProtector>(() => new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider().Create("ASP.NET Identity"));
How is the container supposed to know which implementation of ITextEncoder you want to use in the constructor of SecureDataFormat?
You have to tell it which one to use. I think the rules basically go something like this:
if an interface is required (by a constructor) then it needs to know which implementation to use. If a concrete class is required it will automatically build an instance of that class (assuming it can resolve all the types that class needs).
As your SecureDataForms needs an interface you have to register one, otherwise its only option would be to 'guess' at which implementation you want and this could then go wrong silently if more than one implementation existed.
I just came up against this issue. I'm using ninject but you'll get the idea. Here is my binding:
kernel.Bind<ITextEncoder>().To<Base64UrlTextEncoder>();
According to the source, the only thing I ever see being used to new up an instance of SecureDataFormat is Base64UrlTextEncoder. So it seemed like a safe bet to use, but it's certainly not clear to me at first glance how to appropriately use this constructor overload.
I created a custom membership provider
public class MyMembership : MembershipProvider
{
private IRepository<User> Repo;
}
I figured out how to inject MyMembership using autofac:
builder.Register(c => Membership.Provider);
However, this doesn't work if I have a constructor that takes an IRepository (it only calls the parameterless constructor.) I tried doing changing from a private field to a public property and calling:
builder.Register(c => Membership.Provider).AutoWireProperties();
The problem is, MembershipProvider doesn't have a Repo property, it's only my class.
For the time being, I've not injected anything, and just created an empty constructor where I simply create a new instance of my Repo. But it makes it harder for testing.
So, is there any way that I can use AutoFac to inject my MyMembership, and have it use the injected Repo?
No. It's not possible.
The DependencyResolver is not used for the providers (roles/membership) etc.
I've made a membership provider which uses DependencyResolver internally. All you need to do is to implement IAccountRepository and register it in your container.
http://blog.gauffin.org/2011/09/a-more-structured-membershipprovider/
It's an old post, so i'll just post here my solution as I struggle with it a bit myself.
public class AutofacBootstrapperImp : AutofacBootstrapper
In your autofac builder setup include register for your interface
builder.RegisterType<YourRepo>().As<IRepository<User>>().SingleInstance();
public class CustomMembershipProvider : MembershipProvider
Overload init method and use autofac scope to resolve your type
private IRepository<User> Repo;
public override void Initialize(string name, NameValueCollection config)
{
// use autoface scope to resole service
using (var scope = AutofacBootstrapper.Container.BeginLifetimeScope())
{
Repo = scope.Resolve<IRepository<User>>();
}
if (config == null)
throw new ArgumentNullException("config");
// Initialize the abstract base class.
base.Initialize(name, config);
}
You should also register the IRepository<User>. But to do that you need to access your custom provider by its concrete type.
So something like this:
builder.Register( c => Membership.Provider );
builder.Register( c => ((MyMembership) Membership.Provider).Repo );
That could be made nicer (avoiding casts by registering your implementation) as follows, but not sure on how it then fits in with ASP.NET and its management of provider lifecycles:
builder.RegisterType<MyMembership>();
builder.Register( c => c.Resolve<MyMembership>() ).As<MembershipProvider>();
builder.Register( c => c.Resolve<MyMembership>().Repo );
EDIT:
but from a design standpoint, it looks like your MyMembership class has a dependency on the IRepository<User>, therefor something like this is probably best:
builder.RegisterType<YourRepositoryImplementation>().As<IRepository<User>>();
builder.RegisterType<MyMembership>();
builder.Register( c => c.Resolve<MyMembership>() ).As<MembershipProvider>();
That way the IRepository will be injected into the MyMembership as needed, but also be available for direct consumption by other components, and they all have the lifetime management handled by Autofac.
This scenario is entirely possible. In my Bootstrapper.cs class, I just inject the properties into the providers as such:
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
var lifetimeScope = DependencyResolver.Current.GetService<ILifetimeScope>();
lifetimeScope.InjectProperties(Membership.Provider);
lifetimeScope.InjectProperties(Roles.Provider);
I also have the following:
builder.Register(context => Membership.Provider).ExternallyOwned();
builder.Register(context => Roles.Provider).ExternallyOwned();
however I'm not entirely sure if it's even necessary. I believe the Registers are there in case you want to inject the provider into a type.
Should I do something along the lines of this? I'm thinking of all my controllers inheriting from BaseController. Does this break the design pattern of IoC? What else should I do instead?
public class BaseController: Controller
{
protected ICookieService CookieService {
get {
return ServiceResolver.Resolve<ICookieService>(new { HttpContext = HttpContext });
}
}
protected IDateTimeService DateTimeService {
get {
return ServiceResolver.Resolve<IDateTimeService>();
}
}
protected ISettingsService SettingsService {
get {
return ServiceResolver.Resolve<ISettingsService>();
}
}
}
It would be a lot simpler to go with constructor injection and have a controllerfactory inject it for you. If you can, don't use a service locator (your ServiceResolver ) if you can get away with constructor injection.
There's some info on it on Adding a controller factory to ASP MVC
The link shows how to do it with StructureMap and it looks like you're using Unity, but it should be straightforward to adapt.
I'm assuming that the protected interfaces you have are dependencies for the controller. Its possible to set up an IoC container to inject the dependencies for you. It can certainly be done with Castle Windsor. You would need to change you BaseController class to have a constructor with the required dependencies, as long as the IoC container knows about the other services it'll be able to inject them.
One of the principles behind Inversion of Control and Component-Driven Development is about using static service locators only when there is no other way (i.e.: in web service hosts or object data sources).
Technically speaking, using static service locators the base controller does not violate IoC, it just does not use it.
Check out existing integration between Autofac IoC container and ASP.NET MVC (other containers should be able to do that as well).