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.
Related
I am trying to use an option pattern with Autofac and every attempt has just resulted in errors.
What I've tried:
Using the ConfigurationBuilder to retrieve an IConfiguration/IConfigurationRoot.
Register an instance of TestSectionOptions using the IConfiguration/IConfigurationRoot that was created before:
builder.Register(c => config.GetSection("TestSection").Get<TestSectionOptions>());
Trying to inject it via constructor injection:
private readonly TestSectionOptions _options;
public DemoClass(IOptions<TestSectionOptions> options)
{
_options = options.Value;
}
I'm getting following error:
DependencyResolutionException: None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'DemoApp.DemoClass' can be invoked with the available services and parameters:
Cannot resolve parameter
'Microsoft.Extensions.Options.IOptions1[DemoApp.TestSectionOptions] options' of constructor 'Void .ctor(Microsoft.Extensions.Options.IOptions1
Of course I tried other types of registration, but none of them worked.
I also know that I can simply bind the configuration file to a class, which I then register and inject without the IOptions<> part. But that would no longer correspond exactly to the option pattern, would it?
Even if it doesn't make a big difference, I'd still like to know why it doesn't work and how I could get it to work.
The problem is that this IOptions type should be registerd somewhere.
You can see e.g. this article. There is an example
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PositionOptions>(Configuration.GetSection(
PositionOptions.Position));
services.AddRazorPages();
}
So, somewhere inside Configure extension method it registers types for options, among others IOptions<>.
So, in your case you either have to do this explicitly, like
builder.Register(c => Options.Create(config.GetSection("TestSection").Get<TestSectionOptions>()))
This will register IOptions
or, you can create an empty service collection, then call Configure method on it, and then copy all registrations to autofac builder - there is Populate method from the package "Autofac.Extensions.DependencyInjection"
https://autofac.org/apidoc/html/B3162450.htm
I am new to ASP.Net Core and I am trying to implement ASP.NET Core DI.
I configured like below in ConfigureServices Method in Startup.cs
services.AddScoped<DbContext, AutomationDbContext>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<IUserService, UserService>();
In UserService Constructor, I am trying to use DI. I think below is NOT the right way to implement this.
public UserService(IHttpContextAccessor httpContextAccessor, AutomationDbContext automationDbContext, IConfiguration configuration)
{
this.configuration = configuration;
this.optionsBuilder = new DbContextOptionsBuilder<AutomationDbContext>();
var connectionString = this.configuration.GetConnectionString("Automation");
this.optionsBuilder.UseSqlServer(connectionString);
this.automationDbContext = new AutomationDbContext(this.optionsBuilder.Options);
this.httpContext = httpContextAccessor.HttpContext;
}
I don't like building optionsbuilder in constructor and get connectionstring.
What would be the better place to build these optionsBuilder and pass in constructor.
You need to use services.AddDbContext<TContext> instead:
services.AddDbContext<AutomationDbContext>(o =>
o.UseSqlServer(Configuration.GetConnectionString("Automation")));
Then, just inject your context:
public UserService(IHttpContextAccessor httpContextAccessor, AutomationDbContext automationDbContext)
As for IHttpContextAccessor, you should simply use:
services.AddHttpContextAccessor();
However, I would encourage you to strongly consider whether you actually need this in your service or not. If you need something like the current user's id, that should be passed into the method that needs it, not retrieved from within your service.
UPDATE
Since it was brought up, let me elucidate the reasons why adding your context in the way you currently are is incorrect, since it will shed a little light on how DI works in general.
First, you're binding DbContext directly to AutomationDbContext, which means you can then only use that one context. Maybe you don't need more than one context... now. That could change later. Second, when you register a service in that way, you can only inject the abstract type, i.e. DbContext here. The service registration literally means "when you see DbContext, inject an instance of AutomationDbContext". If you try to inject AutomationDbContext directly, as you're currently doing in your controller, that will actually throw an exception because that type is not actually registered as service: DbContext is. Third, AddScoped provides no real ability to configure the context, which is of course the part your were missing. There's ways to work around this such as using the factory overload of AddScoped or defining OnConfiguring on your context, but both of those are substandard to just using the right method in the first place: AddDbContext<TContext>
For what it's worth, there's also somewhat of a fourth reason, in that you can opt to use AddDbContextPool<TContext> instead of AddDbContext<TContext>, for connection pooling. There's no other way to set that up, so if you did want/need connection pooling, you'll never get there with AddScoped.
The issue was noticed with the call to the extension method container.RegisterWebApiControllers(GlobalConfiguration.Configuration) on the container that's supposed to register the web api controller with the container but didn't. Please note that the web api controllers are defined in a different class library project and plugged at application start up using a custom IAssembliesResolver type.
public static class SimpleInjectorWebApiInitializer
{
public static void Initialize()
{
var container = new Container();
GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver),
new ApiAssemblyResolver());
InitializeContainer(container);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
}
I even tried to call to get the ControllerTypes manually to see what was going on using the code below but it never triggered the GetAssemblies method neither did it return any ControllerTypes.
var controllerTypes = httpConfigServicesContainer.GetHttpControllerTypeResolver()
.GetControllerTypes(
GlobalConfiguration.Configuration.Services.GetAssembliesResolver());
I am almost pulling out all my hair as I can't seem to see what I am doing wrong. Thanks for your help in advance.
It's hard to be very specific, but here's a list of things that might be causing your controllers to not be registered:
Your ApiAssemblyResolver does not return the assembly that holds the controllers.
That assembly is a dynamic assembly (meaning that Assembly.IsDynamic returns true). Web API will skip dynamic assemblies.
The controller types are internal. Web API only uses public types.
The controller types are not classes (but structs).
Their type name does not end with "Controller"
They don't implement IHttpController.
Your IAssembliesResolver isn't registerd correctly (perhaps you are missing a binding redirect, causing your application to reference two versions of Web API). Tip: Check what for type GlobalConfiguration.Configuration.Services.GetAssembliesResolver() actually resolves.
Also try the following:
var controllerTypes = httpConfigServicesContainer.GetHttpControllerTypeResolver()
.GetControllerTypes(new ApiAssemblyResolver());
Does this result in any controllers? In that case, there is probably something miss with the call to Replace(typeof(IAssembliesResolver).
The solution lay in the order in which configuration calls were made. I moved every call for configuration involving the IOC container into the Application_Start method of Global.asax file.
Before making the call to GlobalConfiguration.Configure(WebApiConfig.Register),
I had already called
GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver), new ApiAssemblyResolver())
to replace the default assemblies resolver. I finally placed the other container web api configuration settings after every other configuration call and it started working like a charm! I.e
var apiIOCContainer = new Container();
SimpleInjectorWebApiInitializer.InitializeContainer(apiIOCContainer);
apiIOCContainer.RegisterWebApiControllers(GlobalConfiguration.Configuration);
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(apiIOCContainer);
I'm using Mvc3 and Unity.Mvc3 to build a testable and decoupled site, but I'm obviously doing something wrong.
In my Application_Start() i register a dependency:
// container is a property of the MvcApplication
// and the HierarchicalLifetimeManager should make sure that the registrations
// only last for this request (or should it?)
_container.Register<Interface, Class>(new HierarchicalLifetimeManager())
Then in the Session_Start() i try to resolve my dependency to save some data into the session:
var obj = _container.Resolve<Interface>();
At this point I get an exception saying that Unity can't resolve an interface, but I thought I registered a class for that interface???
I'm at a loss, and it's getting harder and harder to find a solution.
EDIT:
Here's my whole code, with some unnecessary parts left out:
public class MvcApplication : System.Web.HttpApplication
{
// as EDIT 2 says, this is wrong...
//private IUnityContainer _container = new UnityContainer();
protected void Application_Start()
{
// mvc stuff, routes, areas and whatnot
// create container here and it works, almost
var container = new UnityContainer();
// register dependencies
string connectionString = "String from config";
container.RegisterInstance<DbContext>(new CustomContext(connectionString), new HierarchicalLifetimeManager())
.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager())
.RegisterType(typeof(IRepository<>), typeof(Repository<>), new HierarchicalLifetimeManager());
// register controller resolver
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
// if i try to resolve repos here, it works and they all have the same context
// just like the unit of work
}
protected void Session_Start()
{
// here the container complains that it can't resolve the interface
// wrong
//var userRepo = _container.Resolve<IRepository<User>>();
// right, but still failes, because it is resolving DbContext
// instead of using the CustomContext instance
var userRepo = DependencyResolver.Current.GetService<IRepository<User>>();
// save some user data to session
}
}
public class SampleController : Controller {
// here the container tries to resolve the System.Data.Entity.DbContext
// instead of just giving the repo that instance that I registered
public SampleController(IRepository<Entity> repo) {
}
}
I'm obviously failing miserably at this Unit-of-work, dependency injection stuff, and the worst part is that I don't know why...
So please help before I start pulling my teeth out.
EDIT 2:
Partly there. If i create the container as above, it fails in the Session_Start(). If i create it in the Application_Start() as a local variable, and use the DependencyResolver, it works. How and why, beats me?
But it's still trying to resolve the DbContext instead of the CustomContext instance.
SOLUTION:
Ok, so here's the deal:
Problem 1) accessing the container in Session_Start():
As described in the EDIT 2, using a local container variable solves that, and accessing the container via the DependencyResolver works.
Problem 2) resolving the registered db context instance:
It turns out that registering an instance does not work.
This does though:
container.RegisterType<DbContext, CustomContext>(null, new HierarchicalLifetimeManager(), new InjectionConstructor(connectionString))
But I don't really feel satisfied, because I still didn't figure out why this works like this. Looks like I need to read a book or something for once in a long time.
Many thanks in advance.
The problem is you're using RegisterInstance with the HierarchecalLifetimeManager. I'm guessing you're trying to get a new instance per request, because the Unity.Mvc3 project uses that LifetimeManager to work that magic (as well as HttpModules to manage the creation and destruction of child containers).
The problem is, as a new request comes in, it will want to construct a new object, but doesn't know how to; you just registered an instance once, at the app start, and not a way to make an object. So you need to use RegisterType() for that to work.
You have two choices:
Specify the injected value using an InjectionConstructor: RegisterType<DbContext, CustomContext>(new HierarchecalLifetimeManager(), new InjectionConstructor(connectionString))
Use a factory: Container.RegisterType<DbContext>(new InjectionFactory(c => new CustomContext(connectionString)), new HierarcicalLifetimeManager()) (inspired by this)
*Note: parameter order may be wrong.
If you want a true singleton instance for your entire application, use the ContainerControlledLifetimeManager() (which is actually the default for RegisterInstance, so you don't even need to specify it). But then your DbContext will get rather huge as the site gets used.
Additionally, on your initial problem with the items not being registered in Session_Start():
ASP.NET maintains a pool of HttpApplication classes. That means if you make the Unity container a member variable, you'll have several instances which all have their own registrations. Application_Start() is called only once, and Session_Start() could be called using a different instance with no registrations. You'd need to use a static variable to solve that (which is what you ended up doing with the DependencyResolver).
Instead of accessing the container directly (it's not clear from your Q where you got the reference to the container?), why not let the MVC dependency resolver resolve it?
Set the Dependency resolver (Application_Start()):
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Resolve your interface (Session_Start()):
var obj = DependencyResolver.Current.GetService<IMyInterface>();
I did my configuration like this:
var container = new Container(x =>
{
x.For<IEngine>().Use<V6Engine>();
x.For<ICar>().Use<HondaCar>();
}
);
Then in my mvc controller action I did:
ICar car = ObjectFactory.GetInstance<ICar>();
Should I be setting up my container using Container or ObjectFactory somehow? It didn't resolve, so I tested things out in a c# console application and it worked if I did:
ICar car = container.GetInstance<ICar>();
But this only works if container is in local scope, and in a web app it isn't obviously since things are wired up in global.asax.cs
ObjectFactory is a static gateway for an instance of container. If you only ever want one instance of a container, and want a simple static way to get at it, use ObjectFactory. You must Initialize the ObjectFactory, and then retrieve your instances via ObjectFactory.
Alternatively, if you want to manage the lifetime of the container yourself, you can create an instance of Container, passing an initialization expression to the constructor. You then retrieve instances from the variable you declared to store the Container.
In your example, you are mixing the two approaches, which doesn't work.
I have got mine configured as below
global.asax
ObjectFactory.Initialize(action =>
{
action.For<ISomething>().Use<Something>;
});
Then everywhere else.
ObjectFactory.GetInstance<ISomething>();
This may not be the only way though. Also I think what you might be looking for is the
Scan(scanner =>
{
scanner.AssemblyContainingType(....);
scanner.AddAllTypesOf(....);
}