Hey it's my first post so I'm ask for understanding. I've looked many posts but I didn't find solution.
I want to implement custom membershiprovider class with:
namespace Mvc_car.Authorization
{
public class SimpleMembershipProvider : MembershipProvider
{
private NHibernateRepository<Uzytkownik> repo;
ISession session;
[Inject]
public SimpleMembershipProvider(ISession session)
{
this.session = session;
}
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
repo = new NHibernateRepository<Uzytkownik>(session);
base.Initialize(name, config);
}
my bindings:
kernel.Bind<ISession>().ToMethod(x => MvcApplication.SessionFactory.OpenSession()).InRequestScope();
kernel.Bind(typeof(IRepository<>)).To(typeof(NHibernateRepository<>));
kernel.Inject(Membership.Provider); //either with or without that
I've changed in web.config:
<membership defaultProvider="MyMembershipProvider">
<providers>
<clear/>
<add name="MyMembershipProvider" type="Mvc_car.Authorization.SimpleMembershipProvider"/>
</providers>
</membership>
after try of logging following error occurs:
This method cannot be called during the application's pre-start initialization stage.
The solution to this is pretty simple. In your class containing the PreApplicationStartMethod attribute, add a static method like this.
public static class NinjectWebCommon
{
public static void InjectProviders()
{
Bootstrapper.Kernel.Inject(Membership.Provider);
Bootstrapper.Kernel.Inject(Roles.Provider);
}
...
}
When setting up your Provider, dont inject the dependencies through the constructor. Instead decorate the properties with an [Inject] attribute like this.
public class DefaultMembershipProvider : MembershipProvider
{
[Inject]
public IUserRepository UserRepository { get; set; }
}
After that, its as simple as calling NinjectWebCommon.InjectProviders() from your global.asax Application_Start() method.
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
NinjectWebCommon.InjectProviders();
...
}
}
Related
Since asp.net core DI provides only constructor injection and method injection.
If there's a lot of services to inject.
Instead of writing a lot inside constructor and change constructors frequently.
Can I just use some kind of provider so that I can get the services everywhere inside controller?
Instead of :
public class HomeController : BaseController
{
public HomeController(
IEmailService emailService,
ISMSService smsService,
ILogService logService,
IProductRepository _productRepository)
:base(emailService,smsService,logService)
{
}
public IActionResult()
{
_emailService.SendSomething();
}
...
}
public class BaseController : Controller
{
protected readonly IEmailService _emailService;
protected readonly ISMSService _smsService;
protected readonly ILogService _logService;
public BaseController(
IEmailService emailService,
ISMSService smsService,
ILogService logService)
{
_emailService = emailService;
_smsService = smsService;
_logService = logService;
}
}
With some kind of provider like:
public class HomeController : BaseController
{
public HomeController(IDIServiceProvider provider)
:base(provider)
{
}
public IActionResult()
{
_provider.GetScopedService<IEmailService>().SendSomething();
}
...
}
public class BaseController : Controller
{
protected readonly IDIServiceProvider _provider;
public BaseController(IDIServiceProvider provider)
{
_provider = provider;
}
}
So that I don't have to change all controller's constructors every time when BaseController's constructor changes and simplify all controller's constructors.
You can inject IServiceProvider to your controller and get your dependencies from that but it's not DI anymore and it's called Service Locator pattern.
public class HomeController
{
private readonly ITestService _testService;
public HomeController(IServiceProvider serviceProvider)
{
_testService = serviceProvider.GetRequiredService<ITestService>();
}
}
It's recommended to not use Service Locator because :
1- Your controller dependencies are not obvious with the first look.
2- It's harder to write unit tests for that.
3- Your service now needs one more dependency (IServiceProvider).
Use Service Locator pattern only when it needed like injecting your dependencies to FilterAttributes or ValidationAttributes. ( You can use ServiceFilter for this situations too. )
I have the following two classes
public class RepositoryConnection : IRepositoryConnection{
public RepositoryConnection(IConfiguration configuration, ILogger<RepositoryConnection> logger){
//STUFF
}
}
public class AuthenticationTokenFactory : IAuthenticationTokenFactory {
public AuthenticationTokenFactory(ILogger<AuthenticationTokenFactory> logger) {
//STUFF
}
}
Here is my Startup.cs
public class Startup {
public Startup(IConfiguration configuration) {
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services) {
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IAuthenticationTokenFactory, AuthenticationTokenFactory>();
services.AddSingleton<IRepositoryConnection,RepositoryConnection>();
}
}
I can successfully inject IAuthenticationTokenFactory to controllers but when i try to inject IRepositoryConnection i get the following error→
InvalidOperationException: No service for type 'TrainingCommerce.Accessors.RepositoryConnection' has been registered.
Thanks to comments i immediately noticed my wrongful ways.
I was trying to access at another line
var debug = ControllerContext.HttpContext.RequestServices.GetRequiredService<RepositoryConnection>();
Try injecting the interface instead of the implementation:
In your sample you inject ILogger<RepositoryConnection> logger this is a typo and should be: ILogger<IRepositoryConnection> logger.
So:
public class RepositoryConnection : IRepositoryConnection{
public RepositoryConnection(IConfiguration configuration, ILogger<IRepositoryConnection> logger){
//STUFF
}
}
I am using the following DTO class in one of my api controller class, in an asp.net core application.
public class InviteNewUserDto: IValidatableObject
{
private readonly IClientRepository _clientRepository;
public InviteNewUserDto(IClientRepository clientRepository)
{
_clientRepository = clientRepository;
}
//...code omitted for brevity
}
This is how I using it in a controller
[HttpPost]
public async Task<IActionResult> RegisterUser([FromBody] InviteNewUserDto model)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
//...omitted for brevity
}
But I am getting a System.NullReferenceException in the DTO class
This is happening since dependency injection is not working in the DTO class.
How can I fix this ?
DI will not resolve dependences for ViewModel.
You could try validationContext.GetService in Validate method.
public class InviteNewUserDto: IValidatableObject
{
public string Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
IClientRepository repository = (IClientRepository)validationContext.GetService(typeof(IClientRepository));
return null;
}
}
Did you register ClientRepository in startup.cs?
public void ConfigureServices(IServiceCollection services)
{
...
// asp.net DI needs to know what to inject in place of IClientRepository
services.AddScoped<IClientRepository, ClientRepository>();
...
}
I want to be able to create a database context with entityframework core in my webapi project using the database first approach.
When I create like this it works very well
public class TestingContext : DbContext
{
public TestingContext(DbContextOptions<TestingContext> options)
: base(options)
{
}
public TestingContext()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=xxxxxx;Initial Catalog=xxxxxx;Integrated Security=False;User Id=xxxxx;Password=xxxxx;MultipleActiveResultSets=True");
}
public DbSet<Information> Information { get; set; }
public DbSet<ArticleUser> ArticleUser { get; set; }
}
I had to add the line services.AddDbContext to make it work.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddCors();
//using Dependency Injection
services.AddSingleton<Ixxx, xxx>();
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddDbContext<TestingContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "Articles API", Version = "v1" });
});
}
If I remove this method from my TestingContext
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=xxxxxx;Initial Catalog=xxxxxx;Integrated Security=False;User Id=xxxxx;Password=xxxxx;MultipleActiveResultSets=True");
}
I get the error below.
No database provider has been configured for this DbContext.
A provider can be configured by overriding the DbContext.OnConfiguring method or
by using AddDbContext on the application service provider. If AddDbContext is used,
then also ensure that your DbContext type accepts a DbContextOptions object in its
constructor and passes it to the base constructor for DbContext.
Why do I need to pass my connection string to the database in two places before it can pull my data. Please assist. I am new to the core. The two places are configure services method and the context itself.
Option 1: Remove parameterized constructor and OnConfiguring. Result:
public class TestingContext : DbContext
{
public DbSet<Information> Information { get; set; }
public DbSet<ArticleUser> ArticleUser { get; set; }
}
Option 2: Remove parameterized constructor and options in ConfigureServices in AddDbContext
Result:
In Startup.cs
services.AddDbContext<TestingContext>();
In TestingDbContext.cs
public class TestingDdContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=xxxxxx;Initial Catalog=xxxxxx;Integrated Security=False;User Id=xxxxx;Password=xxxxx;MultipleActiveResultSets=True");
}
public DbSet<Information> Information { get; set; }
public DbSet<ArticleUser> ArticleUser { get; set; }
}
Option 3: A parametric constructor is needed to create factory. Example:
public class TestDdContext : DbContext
{
public TestDdContext(DbContextOptions options) : base(options)
{
}
//TODO: DbSets
}
public class TestDbContextFactory : IDbContextFactory<TestDdContext>
{
public TestDdContext Create(DbContextFactoryOptions options)
{
var contextOptions = new DbContextOptionsBuilder();
contextOptions.UseSqlServer("...");
return new TestDdContext(contextOptions.Options);
}
}
If you are creating tests, do you need a backing Sql database? Would the In-memory provider not serve you better?
options.UseInMemoryDatabase("database-name");
For this reason, I'd ditch using the OnConfiguring method, and rely on passing the DbContextOptions to your constructor
Side note, you have to consider what you are testing - are you testing your code that is dependent on your DbContext, or are you testing your DbContext itself - if there is no custom logic and you are merely extending the DbContext, there may not be enough value in writing tests for it - and you're not responsible for testing EFCore itself.
Im very new but on a quest to learn nhibernate and DI with structuremap so am making an app to test everything out.
I am having some problems injecting my unitofwork into my base repository. I create a unitofwork on every request then either commit or rollback at the end. But when tryin to inject into my base repository its always null when i go to use it in my methods. More specifically i get this error: "Object reference not set to an instance of an object". Any ideas what im doing wrong and if this is the correct route i should be going?
Many thanks in advance.
Base Repository:
public abstract class Repository<T> : IRepository<T>
{
public readonly IUnitOfWork _unitOfWork;
public Repository(IUnitOfWork UnitOfWork)
{
UnitOfWork = _unitOfWork;
}
public Repository() {}
public void Save(T obj)
{
_unitOfWork.CurrentSession.Save(obj);
}
}
StructureMap registry thats set in my application_start:
public class NHibernateRegistry : Registry
{
public NHibernateRegistry()
{
For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>();
For<ISession>().HybridHttpOrThreadLocalScoped().Use(context => context.GetInstance<ISessionFactory>().OpenSession());
For<ISessionFactory>().Singleton().Use(NHibernateSessionFactory.GetSessionFactory());
}
}
Update:
The baserepository is inherited by specific repositorys ie ArticleRepository then im injecting that into my aspx pages on application_start. Then my aspx page inherits a basepage where the buildUp takes place. And i access the repository like this:
public IArticleRepository ArticleRepo { get; set; }
public void SaveThing()
{
ArticleRepo.Save(object);
}
This gets called on application_start:
public class Bootstrapper
{
public static void BootStrap()
{
ObjectFactory.Configure(x =>
{
x.AddRegistry<NHibernateRegistry>();
x.AddRegistry<WebRegistry>();
});
}
}
And in the webregistry:
For<IArticleRepository>().Use<ArticleRepository>();
There is a good chance your ArticleRepository doesn't have a constructor that takes an IUnitOfWork as a parameter make sure you have the following
public class ArticleRepository : Repository<Article>
{
public ArticleRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
...
}
Remember Strcuture map uses the greediest constructor on the class that it instantiates. Since your abstract repository class will never be instantiated it will not use its constructors. I would also suggest not having any default constructors if your classes need to have their dependencies injected that way. Less chance for errors that way.
public readonly IUnitOfWork _unitOfWork;
public Repository(IUnitOfWork UnitOfWork)
{
UnitOfWork = _unitOfWork;
}
I think you mean to write
public readonly IUnitOfWork _unitOfWork;
public Repository(IUnitOfWork UnitOfWork)
{
_unitOfWork = UnitOfWork;
}
You were assigning the local variable to the parameter instead of the parameter to the local variable.
Edit: Also you should write your parameter with a lowercase U 'unitOfWork' instead of 'UnitOfWork'