MVC controller injection with custom base controller not working - asp.net-mvc-3

I am using StructureMap for DI and am having an issue with my MVC3 custom base controller not being instantiated correctly. Instead of being passed an instance of IAuctionCmsServices, I am getting null.
My controllers:
public class BaseController : Controller
{
public IAuctionCmsServices AuctionCmsServices;
public BaseController()
: this(null) <--- is this the problem?
{
}
public BaseController(IAuctionCmsServices auctionCmsServices)
{
this.AuctionCmsServices = auctionCmsServices;
}
}
public class HomeController : BaseController
{
public ActionResult Index()
{
return View);
}
}
StructureMap code:
public class StructureMapContainer : IDependencyResolver
{
static IContainer _container;
public StructureMapContainer(IContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
if (serviceType.IsAbstract || serviceType.IsInterface)
{
return _container.TryGetInstance(serviceType);
}
else
{
System.Diagnostics.Debug.WriteLine(_container.WhatDoIHave());
return _container.GetInstance(serviceType);
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances<object>().Where(s => s.GetType() == serviceType);
}
}
public class ApplicationRegistry : Registry
{
public ApplicationRegistry()
{
For<IAuctionCmsServices>().HybridHttpOrThreadLocalScoped().Use<AuctionCmsServices>();
}
}
In global.asax.cs:
DependencyResolver.SetResolver(new StructureMapContainer(container));
When BaseController's constructor is invoked, the IAuctionCmsServices parameter is null. If I remove the this(null) from the constructor, I still get null.
Perhaps my BaseController's paramterless constructor is not written correctly? If I resolve for IAuctionCmsServices manually, it works. This means that IAuctionCmsServices is registered correctly but not being injected.

Did you leave out the constructor HomeController from the sample or do you not have one?
Im not really familiar with StructureMap, so unless it does some wizardry with the IL, how is the property supposed to be injected into HomeController if it does not have a constructor that accepts it?
IE
public HomeController(IAuctionCmsServices auctionCmsServices)
: base(auctionCmsServices)
{}
Apologies if Im being dense or missing something.

Related

ASP.NET Core Web API : dependency injection based on runtime parameter value

I am working on an ASP.NET Core Web API application. My API will accept a country name as one of the input parameter from request body.
Due to nature of the application, we have country wise database with same schema. I have created DbContext for one of the databases and want to initialize the DbContext by the passing the connection string based on input request parameter value.
I have created factory method to return the needed database context based on the parameter passed to the factory method. However, the challenge I am facing is, while initializing the factory class as DI from controller, object of factory class is instantiated before the controller action is called. Hence, parameter value in factory method is empty.
How can I pass a parameter in runtime to initialize an object using dependency injection?
Here is the code...
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
public class MyDBContext : DbContext
{
public MyDBContext(DbContextOptions<MyDBContext> options)
: base(options)
{
}
public virtual DbSet<Student> Students { get; set; }
}
public interface IDbContextFactory
{
public MyDBContext GetDbContext(string
connectionString);
}
public class DbContextFactory : IDbContextFactory
{
public MyDBContext GetDbContext(string connectionString)
{
MyDBContext context = null;
if (!string.IsNullOrWhiteSpace(connectionString))
{
DbContextOptionsBuilder<MyDBContext> _dbContextOptionsBuilder = new DbContextOptionsBuilder<MyDBContext>().UseSqlServer(connectionString);
context = new MyDBContext(_dbContextOptionsBuilder.Options);
}
return context;
}
}
public interface IRepository
{
Student GetData();
}
public class Repository : IRepository
{
private MyDBContext _context;
public Repository(IDbContextFactory dbContextFactory)
{
// Here I need connection string based on input parameter (country) from request to dynamically generate country specific connection string
string connectionString = string.Empty;
_context = dbContextFactory.GetDbContext(connectionString);
}
public Student GetData()
{
return _context.Students.FirstOrDefault();
}
}
public interface IServiceAgent
{
Student GetData();
}
public class ServiceAgent : IServiceAgent
{
IRepository _repository;
public ServiceAgent(IRepository repository)
{
_repository = repository;
}
public Student GetData()
{
return _repository.GetData();
}
}
[ApiController]
[Route("[controller]")]
public class HomeController : ControllerBase
{
private readonly IServiceAgent _serviceAgent;
public HomeController(IServiceAgent serviceAgent)
{
_serviceAgent = serviceAgent;
}
[HttpGet]
public Student Get(string country)
{
return _serviceAgent.GetData();
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddScoped<IServiceAgent, ServiceAgent>();
services.AddScoped<IRepository, Repository>();
services.AddScoped<IDbContextFactory, DbContextFactory>();
services.AddScoped<DetermineCountryFilter>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}

Unable to resolve service for type with our own class

We are getting this exception when calling a web api controller:
InvalidOperationException: Unable to resolve service for type 'SDS.Lambda.Interfaces.ISecretManager' while attempting to activate 'SDS.Lambda.Controllers.SapController'.\r\n <p class="location">Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
StartUp.cs contains the following:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ISecretManager, SecretManager>();
}
The controller has this constructor:
public class SapController : Controller
{
public SapController(ISecretManager secretManager)
{
_secretManager = secretManager;
}
}
We have the same issue with other types being injected into the constructor, but the IConfiguration instance can be injected, for example that parameter does not cause an exception:
public SapController(IConfiguration configuration, ISecretManager secretManager)
The ISecretManager interface looks like this (yes, it really does):
namespace SDS.Lambda.Interfaces
{
public interface ISecretManager
{
}
}
And the class (yes, really - I reduced it down to avoid complexity):
namespace SDS.Lambda.Interfaces
{
public class SecretManager : ISecretManager
{
}
}
Are we providing the interface/concrete type incorrectly?
Is there a way to retrieve the concrete type to test whether it has been provided properly?
When execution reaches the bottom of ConfigureServices, if we look at the services instance result enumeration, in the debugger view, the types we are injecting are listed, so we can't see why they are failing to be instantiated.
UPDATE
To elaborate and explain the issue with another class/dependency in the same solution:
Controller:
namespace SDS.Lambda.Controllers
{
[Route("api/[controller]")]
public class SapController : Controller
{
readonly IHelper helper;
public SapController(IHelper helpme)
{
helper = helpme;
}
...
}
Interface:
namespace SDS.Lambda.Interfaces
{
public interface IHelper
{
}
}
Class:
namespace SDS.Lambda.Helpers
{
public class Helper : IHelper
{
public Helper()
{
}
}
}
StartUp:
namespace SDS.Lambda
{
public class Startup
{
public static IConfiguration Configuration { get; private set; }
private readonly AppSettings _appSettings;
public Startup(IConfiguration configuration)
{
Configuration = configuration;
_appSettings = configuration.GetSection("AppSettings").Get<AppSettings>();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(logger => logger.AddLambdaLogger());
services.AddSingleton<IHelper, Helper>();
services.AddControllers();
}
...
}

Can you create multiple instances of a class using method injection or some other form of injection?

public interface IFoo {}
public class Foo : IFoo {}
public sealed class NinjaModule : NinjectModule //Appropriately configured in project
{
public override void Load()
{
Bind<IFoo>.To<Foo>.InTransientScope();
}
}
public class SomeOtherClass : ISomeOtherInterface
{
public SomeOtherClass();
public IFoo GetFoo(IFoo foo)
{
return foo;
}
public void GetFoos()
{
foreach (var thing in everything)
{
var localFoo = GetFoo();
localFoo.UniqueProperty = "I am unique";
_fooList.Add(localFoo);
}
}
}
I need my code to look something like that.
Yes, I am fairly new to inject. I am fairly certain that I am missing a basic principle.
Thanks for any help.
I think the best approach here would be to use a factory to create the different Foo instances. And with Ninject and the Factory extension that's pretty easy.
public sealed class NinjaModule : NinjectModule //Appropriately configured in project
{
public override void Load()
{
Bind<IFoo>().To<Foo>().InTransientScope();
Bind<IFooFactory>().ToFactory();
}
}
public interface IFooFactory
{
IFoo CreateFoo();
}
public class SomeOtherClass : ISomeOtherInterface
{
private IFooFactory fooFactory;
public SomeOtherClass(IFooFactory fooFactory)
{
this.fooFactory = fooFactory;
}
public IFoo GetFoo(IFoo foo)
{
return this.fooFactory.CreateFoo();
}
public void GetFoos()
{
foreach (var thing in everything)
{
var localFoo = GetFoo();
localFoo.UniqueProperty = "I am unique";
_fooList.Add(localFoo);
}
}
}
This was a bad question. I figured out this needed to be implemented higher up by the class controlling these implementations.

How to ensure ASP.net Web API controller's parameter is not null?

I created a ASP.net Web API controller like that:
public class UsersController : ApiController
{
//...
public void Put([FromBody]User_API user, long UpdateTicks)
{
user.UpdateTicks = UpdateTicks;
//...
}
}
The "user" parameter will be null if the client does not provide correct arguments. Can I make a global filter to check every parameter like this, and will return a 400 message if any error occurs.
Finally, I got the solution:
public class ModelValidateFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ActionArguments.Any(v => v.Value==null))
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
}
And...
//In Application_Start()
GlobalConfiguration.Configuration.Filters.Add(new ModelValidateFilterAttribute());

Entity framework: ObjectContext and inheritance

I need to have a CRUd operations on my class (CompetenceSpecific).
Competence has three derived classes - CompetenceFunction, CompetenceArea and CompetenceSpecifc
The error I recieved:
There are no EntitySets defined for the specified entity type 'CompetencyManagement.Domain.Entities.CompetenceFunction'. If 'CompetencyManagement.Domain.Entities.CompetenceFunction' is a derived type, use the base type instead. Parameter name: TEntity
How should I correct this? Please suggest a solution that would solve my problem. Thanks
Please check the code below, I removed some parts of the code for simplicity.
--MODEL
public class Competence
{
public int CompetenceID { get; set; }
public int CourseID { get; set; }
...
}
public class CompetenceFunction : Competence
{
}
--REPOSITORY and interfaces
public interface IRepository<T> where T : class
{
T GetById(object id);
IEnumerable<T> GetAll();
IEnumerable<T> Query(Expression<Func<T, bool>> filter);
void Add(T entity);
void Remove(T entity);
}
public abstract class Repository<T> : IRepository<T>
where T : class
{
protected IObjectSet<T> _objectSet;
public Repository(ObjectContext context)
{
_objectSet = context.CreateObjectSet<T>();
}
...
}
public class CompetenceFunctionRepository : Repository<CompetenceFunction>
{
public CompetenceFunctionRepository(ObjectContext context)
: base(context)
{
}
public override CompetenceFunction GetById(object id)
{
return _objectSet.SingleOrDefault(s => s.CompetenceID == (int)id);
}
}
--UNIT oF WORK
public interface IUnitOfWork
{
IRepository<CompetenceFunction> CompetenceFunctions { get; }
IRepository<CompetenceArea> CompetenceAreas { get; }
IRepository<CompetenceSpecific> CompetenceSpecifics { get; }
void Commit();
}
public class UnitOfWork : IUnitOfWork, IDisposable
{
private CompetenceFunctionRepository _competencefunction;
private CompetenceAreaRepository _competencearea;
private CompetenceSpecificRepository _competencespecifc;
public UnitOfWork(ObjectContext context)
{
if (context == null)
{
throw new ArgumentNullException("Context was not supplied");
}
_context = context;
}
#region IUnitOfWork Members
public IRepository<CompetenceFunction> CompetenceFunctions
{
get
{
if (_competencefunction == null)
{
_competencefunction = new CompetenceFunctionRepository(_context);
}
return _competencefunction;
}
}
public IRepository<CompetenceArea> CompetenceAreas
{
get
{
if (_competencearea == null)
{
_competencearea = new CompetenceAreaRepository(_context);
}
return _competencearea;
}
}
public IRepository<CompetenceSpecific> CompetenceSpecifics
{
get
{
if (_competencespecifc == null)
{
_competencespecifc = new CompetenceSpecificRepository(_context);
}
return _competencespecifc;
}
}
--Im getting an error in this part of Repository
public Repository(ObjectContext context)
{
_objectSet = context.CreateObjectSet<T>();
}
There are no EntitySets defined for the specified entity type 'CompetencyManagement.Domain.Entities.CompetenceFunction'. If 'CompetencyManagement.Domain.Entities.CompetenceFunction' is a derived type, use the base type instead. Parameter name: TEntity
Here's how I implement in the controller
private IUnitOfWork _unitOfWork;
var a = _unitOfWork.CompetenceFunctions.GetAll();
return View(a);
You have to get derived type by the OfType function, e.g.
context.CreateObjectSet<Competence>().OfType<CompetenceFunction>()
In your case that would mean that there is only a CompetenceRepository that serves all derivatives of Competence.
Edit
(After your comment)
First, UoW is meant for temporarily storing changes that should be dealt with in one batch (like changes to be committed to the database). GetAll and similar functions are repository stuff.
But do you need repositories? I like this post. When beginning to know EF, I would focus on the ins and outs of EF without getting distracted too much by surrounding architecture. E.g. start with services that at the inside communicate directly with the context and expose methods like GetCompetenceFunctions, GetCompetenceAreas (using OfType), and SaveCompetenceFunction, ....
You can address these service methods directly from action methods in the MVC controllers.

Resources