Repository interface null error when called from HomeController - c#

I was following this tutorial:
http://blog.johanneshoppe.de/2010/10/walkthrough-ado-net-unit-testable-repository-generator/
And I had this issue:
MVC3 & EF. Interface for TDD
However, now I have my interfaces setup (I am not using ninject due to project restrictions)
I am getting a null error here;
`Public partial class MyEntitiesRepository : MyEntitiesRepository
{
public IEnumerable<userdetails> getAlluserDetails()
{
return this.Context.userDetails.ToList();
}`
Context is null. I am using the exact same structure as the tutorial.
The header in my MVC controller that calls this is:
`
[HandleError]
public class HomeController : Controller
{
private MyEntitiesRepository _repository;
...
...
public HomeController() : this(new externalEntities(), new MyEntitiesRepository ()){}
public HomeController(externalEntities external, MyEntitiesRepository repository)
{
_repository = repository;
_ContextExt = external;
}
`
EDIT:
context is from:
[System.CodeDom.Compiler.GeneratedCode("ADO.NET Unit Testable Repository Generator", "0.5")]
public partial class MyEntitiesRepository
{
/// <summary>
/// Gets or sets the specialised object context
/// </summary>
/// <value>object context</value>
#if !DO_NOT_USE_UNITY
[Dependency]
#endif
public IMyEntities Context { get; set; }
}
}

I am guessing that in the example they pass the Context in the constructor. They can do this because they are using dependency injection and it will create that instance for you. Since you are not using Ninject, you will more than likely need to construct this Context yourself.
If you are unable to use Ninject or any other IoC container then you need to do a better job convincing your bosses to let you. If they still don't let you then you can do poor man's dependency injection I suppose:
public class MyEntitiesRepository
{
private MyDbContext context;
public MyEntitiesRepository() : this(new MyDbContext())
{ }
public MyEntitiesRepository(MyDbContext context)
{
this.context = context;
}
}
It's better than nothing I suppose?

Seeing the edit (the Dependency attribute) I guess the project restrictions you are referring to are that instead of Ninject you are to use Microsoft's Unity.
Now you can solve your problem using or not using Unity. To start with the latter: Adjust your HomeController and MyEntitiesRepository classes a little:
public HomeController() :
this(new externalEntities(),
new MyEntitiesRepository (new MyEntities()))
{
}
public HomeController(externalEntities external, MyEntitiesRepository repository)
{
_repository = repository;
_ContextExt = external;
}
public partial class MyEntitiesRepository
{
public MyEntitiesRepository(IMyEntities context)
{
this.Context = context;
}
public IMyEntities Context { get; private set; }
}
Here I made the assumption that you have a class MyEntities implementing the interface IMyEntities.
You could also use Unity. To get to know that framework a little better you could start at MSDN. I don't have any experience with Unity, but some things I noticied are that you need to create MyEntityRepository using a UnityContainer object:
IUnityContainer container = new UnityContainer();
...
MyEntityRepository repository = container.Resolve<MyEntityRepository>();
Before that works you need to register a mapping of MyEntities to IMyEntities:
container.RegisterType<IMyEntities, MyEntities>();
If you choose to try Unity I suggest you give it a try and ask a new question if you get stuck.

Related

Configuring DBContext in the constructor of my base repository class

I have a situation where I need to instantiate my DBContext after my solution has started up. I asked this question which indicated that I could do this with a constructor argument.
It was suggested that I implement as an example this:
var connection = #"Server=(localdb)\mssqllocaldb;Database=JobsLedgerDB;Trusted_Connection=True;ConnectRetryCount=0";
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(connection);
using (var context = new BloggingContext(optionsBuilder.Options))
{
// do stuff
}
However I have implemented the repository pattern (for better or worst) and given my changed circumstances - not having a connection string until after the solution has run startup - I need to implement this into the base repository class and I am at a bit of a loss..
Currently I have this:
public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IEntityBase, new()
{
public JobsLedgerAPIContext _context;
#region Properties
public EntityBaseRepository(JobsLedgerAPIContext context)
{
_context = context;
}
#endregion
public virtual IQueryable<T> GetAll()
{
return _context.Set<T>().AsQueryable();
}
public virtual int Count()
{
return _context.Set<T>().Count();
}
......
How do I implement this change both instantiating the DBContext in the constructor (there by bypassing the need to add the context as a service in startup) and then with the wrapping each of the virtual methods with "using" etc
EDIT.. Camilo indicated I had not identified when I have the database name.
The basic situation is that the system starts up (This is an Aurelia SPA project which is irrelevant to this issue) sends the package to the browser which shows a login screen. User logs in.. User is verified via a JWT controller.. Once verified in the controller (using a catalog database that has one table with 3 fields - username, password, database name) I use the database name to create a connection string and then instantiate my DBContext at that point.. so via a constructor.
The answers below need to be modified as the one with the factory answer (promising) has errors as discovered by this question.. Nkosi responded with an great answer to the error.
EDIT 2..
This is a response to the edited question below:
Here is my original Client Repository with :base(context) on the constructor.
using JobsLedger.DATA.Abstract;
using JobsLedger.MODEL.Entities;
namespace JobsLedger.DATA.Repositories
{
public class ClientRepository : EntityBaseRepository<Client>, IClientRepository
{
private new JobsLedgerAPIContext _context;
public ClientRepository(JobsLedgerAPIContext context) : base(context)
{
_context = context;
}
public void RelatedSuburbEntities(Suburb _suburb)
{
_context.Entry(_suburb).Reference<State>(a => a.State).Load();
}
}
}
It has a reference to the base class "context". I am not sure how to modify this given that I believe I still need that ":base(context)" at the end. As well, I have a method in this that accesses _context as well which is part of the constructor...
Further I assume that I can no longer inject the service into the controller but instead new it up once I have secured the connection string and then pass that connection string to service.
Also, Given I have now added a singleton on the startup do I need to remove the original entry? :
services.AddDbContext<JobsLedgerAPIContext>(options => options.
UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly("JobsLedger.API")));
effectively replacing it with my singleton reference as per below:
services.AddSingleton(typeof(IContextFactory<>), typeof(ContextFactory<>));
Edited
The answer has been edited to rectify the mistake spotted and
fixed by Nkosi. Thanks, #Nkosi.
Implement a factory pattern. You can create a factory, call it ContextFactory as below:
First, define the interface. Further modified, removed the connectionString parameter
public interface IContextFactory<T> where T : DbContext
{
T CreateDbContext();
}
Create a factory class that implements this interface (edited as per Nkosi answer). Further modified to inject IHttpContextAccessor
public class ContextFactory<T> : IContextFactory<T> where T : DbContext
{
private readonly HttpContext _httpContext;
public ContextFactory(IHttpContextAccessor contextAccessor)
{
_httpContext = contextAccessor.HttpContext;
}
public T CreateDbContext()
{
// retreive the connectionString from the _httpContext.Items
// this is saved in the controller action method
var connectionString = (string)_httpContext.Items["connection-string"];
var optionsBuilder = new DbContextOptionsBuilder<T>();
optionsBuilder.UseSqlServer(connectionString);
return (T)Activator.CreateInstance(typeof(T), optionsBuilder.Options);
}
}
Then modify your base repository and make the JobsLedgerAPIContext protected. This context is going to be set by the derived class. Further modified to remove the constructor. It will use the parameterless constructor.
public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IEntityBase, new()
{
protected JobsLedgerApiContext Context { get; set; }
public virtual IQueryable<T> GetAll()
{
return Context.Set<T>().AsQueryable();
}
public virtual int Count()
{
return Context.Set<T>().Count();
}
}
Change your derived class to use IContextFactory. Further modified to use the _contextFactory.CreateDbContext() parameter less method
The IClientRepository should have SetContext method defined.
public class ClientRepository : EntityBaseRepository<Client>, IClientRepository
{
private readonly IContextFactory<JobsLedgerApiContext> _contextFactory;
public ClientRepository(IContextFactory<JobsLedgerApiContext> factory)
{
_contextFactory = factory;
}
// this method will set the protected Context property using the context
// created by the factory
public void SetContext()
{
Context = _contextFactory.CreateDbContext();
}
public void RelatedSuburbEntities(Suburb suburb)
{
Context.Entry(suburb).Reference<State>(a => a.State).Load();
}
}
In the controller, that receives IClientRepository instance, you can set the connection in the HttpContext.Items, which will be valid for the request. This value will then be retrieved by the ContextFactory using IHttpContextAccessor. Then you simply call the _repository.SetContext(); method on the repository.
public class HomeController : Controller
{
private readonly IClientRepository _repository;
public HomeController(IClientRepository repository)
{
_repository = repository;
}
public IActionResult Index()
{
// save the connectionString in the HttpContext.Items
HttpContext.Items["connection-string"] = "test-connection";
// set the context
_repository.SetContext();
return View();
}
}
Make sure you register the IContextFactory in ConfigureServices as open generics and Singleton as below, also register the HttpContextAccessor and IClientRepository
services.AddHttpContextAccessor();
services.AddSingleton(typeof(IContextFactory<>), typeof(ContextFactory<>));
services.AddTransient<IClientRepository, ClientRepository>();
You may define your JobsLedgerAPIContext like this:
public class JobsLedgerAPIContext : DbContext
{
// public DbSet<Job> Jobs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=dotnetcore;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// may need to reflect entity classes and register them here.
base.OnModelCreating(modelBuilder);
}
}

How to Pass Argument to constructor dynamically using structureMap

please note that this is my first project with DI and IoC thank you for all your help.
I am creating a multitenant app, were the application db context change from one tenant to another by providing a dynamic connection string.
while initialize the controllers and providing the connection string to the DAL class i am getting "String connectionString = Required primitive dependency is not explicitly defined"
DbContext:
public partial class DataContext : DbContext
{
public DataContext(string connectionString)
: base(connectionString)
{
}
// rest of the code ....
}
DAL:
public class ManagerDAL : IEntityRepository<TestManager>
{
private readonly DataContext _context;
public ManagerDAL(string connectionString)
{
_context = new DataContext(connectionString);
}
// rest of the code
}
Controller:
public class TestController
{
private ManagerDAL _managerDAL;
// .... different DAL
public TestController()
{
_managerDAL = new ManagerDAL("ConnectionString");
}
// reset of the code
}
Please any help would be much appreciated thank you.

IServiceProvider in ASP.NET Core

I starting to learn changes in ASP.NET 5(vNext)
and cannot find how to get IServiceProvider, for example in "Model"'s method
public class Entity
{
public void DoSomething()
{
var dbContext = ServiceContainer.GetService<DataContext>(); //Where is ServiceContainer or something like that ?
}
}
I know, we configuring services at startup, but where all service collection staying or IServiceProvider?
You have to bring in Microsoft.Extensions.DependencyInjection namespace to gain access to the generic
GetService<T>();
extension method that should be used on
IServiceProvider
Also note that you can directly inject services into controllers in ASP.NET 5. See below example.
public interface ISomeService
{
string ServiceValue { get; set; }
}
public class ServiceImplementation : ISomeService
{
public ServiceImplementation()
{
ServiceValue = "Injected from Startup";
}
public string ServiceValue { get; set; }
}
Startup.cs
public void ConfigureService(IServiceCollection services)
{
...
services.AddSingleton<ISomeService, ServiceImplementation>();
}
HomeController
using Microsoft.Extensions.DependencyInjection;
...
public IServiceProvider Provider { get; set; }
public ISomeService InjectedService { get; set; }
public HomeController(IServiceProvider provider, ISomeService injectedService)
{
Provider = provider;
InjectedService = Provider.GetService<ISomeService>();
}
Either approach can be used to get access to the service. Additional service extensions for Startup.cs
AddInstance<IService>(new Service())
A single instance is given all the time. You are responsible for initial object creation.
AddSingleton<IService, Service>()
A single instance is created and it acts like a singleton.
AddTransient<IService, Service>()
A new instance is created every time it is injected.
AddScoped<IService, Service>()
A single instance is created inside of the current HTTP Request scope. It is equivalent to Singleton in the current scope context.
Updated 18 October 2018
See: aspnet GitHub - ServiceCollectionServiceExtensions.cs
I don't think it is a good idea for an entity (or a model) to have access to any service.
Controllers, on the other hand, do have access to any registered service in their constructors, and you don't have to worry about it.
public class NotifyController : Controller
{
private static IEmailSender emailSender = null;
protected static ISessionService session = null;
protected static IMyContext dbContext = null;
protected static IHostingEnvironment hostingEnvironment = null;
public NotifyController(
IEmailSender mailSenderService,
IMyContext context,
IHostingEnvironment env,
ISessionService sessionContext)
{
emailSender = mailSenderService;
dbContext = context;
hostingEnvironment = env;
session = sessionContext;
}
}
use GetRequiredService instead of GetService, like the example on ASP.NET Core tutorials ( https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/working-with-sql )
documentation on the method:
https://learn.microsoft.com/en-us/aspnet/core/api/microsoft.extensions.dependencyinjection.serviceproviderserviceextensions#Microsoft_Extensions_DependencyInjection_ServiceProviderServiceExtensions_GetRequiredService__1_System_IServiceProvider_
using Microsoft.Extensions.DependencyInjection;
using (var context = new ApplicationDbContext(serviceProvicer.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
Do not use GetService()
The difference between GetService and GetRequiredService is related with exception.
GetService() returns null if a service does not exist.
GetRequiredService() will throw exception.
public static class ServiceProviderServiceExtensions
{
public static T GetService<T>(this IServiceProvider provider)
{
return (T)provider.GetService(typeof(T));
}
public static T GetRequiredService<T>(this IServiceProvider provider)
{
return (T)provider.GetRequiredService(typeof(T));
}
}
Generally you want to have the DI do its thing and inject that for you:
public class Entity
{
private readonly IDataContext dbContext;
// The DI will auto inject this for you
public class Entity(IDataContext dbContext)
{
this.dbContext = dbContext;
}
public void DoSomething()
{
// dbContext is already populated for you
var something = dbContext.Somethings.First();
}
}
However, Entity would have to be automatically instantiated for you... like a Controller or a ViewComponent. If you need to manually instantiate this from a place where this dbContext is not available to you, then you can do this:
using Microsoft.Extensions.PlatformAbstractions;
public class Entity
{
private readonly IDataContext dbContext;
public class Entity()
{
this.dbContext = (IDataContext)CallContextServiceLocator.Locator.ServiceProvider
.GetService(typeof(IDataContext));
}
public void DoSomething()
{
var something = dbContext.Somethings.First();
}
}
But just to emphasize, this is considered an anti-pattern and should be avoided unless absolutely necessary. And... at the risk of making some pattern people really upset... if all else fails, you can add a static IContainer in a helper class or something and assign it in your StartUp class in the ConfigureServices method: MyHelper.DIContainer = builder.Build(); And this is a really ugly way to do it, but sometimes you just need to get it working.
I think the OP is getting confused. Entities should be as “thin” as possible. They should try not to contain logic, and or external references other than navigation properties. Look up some common patterns like repository pattern which helps to abstract your logic away from the entities themselves
Instead of getting your service inline, try injecting it into the constructor.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient(typeof(DataContext));
}
}
public class Entity
{
private DataContext _context;
public Entity(DataContext context)
{
_context = context;
}
public void DoSomething()
{
// use _context here
}
}
I also suggest reading up on what AddTransient means, as it will have a significant impact on how your application shares instances of DbContext. This is a pattern called Dependency Injection. It takes a while to get used to, but you will never want to go back once you do.

RepositoryFactory with Ninject

I'm working on web application (web form). I want to be able to change EntityFrameworkRepositoryFactory to NHibernateRepositoryFactory in the future.
IRepositoryFactory
public interface IRepositoryFactory
{
IProductRepository GetProductRepository();
}
ProductRepository
public class ProductRepository : IProductRepository
{
ExDbContext _db;
public ProductRepository(ExDbContext dbContext)
{
_db = dbContext;
}
public IList<Product> ListProductsByCategoryId(int categoryId)
{
List<Product> productsByCategoryId = _db.Products.Where(x => x.ProductCategoryId == categoryId).ToList();
return productsByCategoryId;
}
}
And there is EntityFrameworkRepositoryFactory.
class EntityFrameworkRepositoryFactory:IRepositoryFactory
{
ExDbContext _db;
public EntityFrameworkRepositoryFactory(ExDbContext dbContext)
{
_db = dbContext;
//
// TODO: Add constructor logic here
//
}
public IProductRepository GetProductRepository()
{
return new ProductRepository(_db);
}
}
How can i make easy for changing this in future ? I want use ninject for access EntityFrameworkRepositoryFactory but I'm stuck. Is there any example for this ?
Thanks.
We will add Ninject to your web application, fix your repository classes and add some Ninject modules to configure dependency injection:
Install Ninject. You can do this easily using the Package Manager Console: Install-Package Ninject.Web -dependencyVersion Highest
Remove your RepositoryFactory. Delete IRepositoryFactory and EntityFrameworkRepositoryFactory. You don't need them. Ninject will create a Repository and provide the dependencies as soon as your application asks for them. You need factories only to have better control of an object's lifetime.
Fix the repository. Let's make things more conventional and use an IEnumerable<Product> to return a read-only collection of products as result of our query. We also use Get as a prefix, as most repository patterns do:
public interface IProductRepository
{
IEnumerable<Product> GetProductsByCategoryId(int categoryId);
}
class EfProductRepository : IProductRepository
{
private readonly ExDbContext db;
public EfProductRepository(ExDbContext dbContext)
{
this.db = dbContext;
}
public IEnumerable<Product> GetProductsByCategoryId(int categoryId)
{
var productsByCategoryId = this.db
.Products
.Where(x => x.ProductCategoryId == categoryId)
.ToArray();
return productsByCategoryId;
}
}
Create a Ninject module. We need to bind our repository implementation to its interface. The Entity Framework DbContext uses the "Unit of Work" pattern, so we also need to make sure that our entity context instances are going to be disposed as soon as a request ends. We could do this using a context factory and the using directive, but we can also use the "Request Scope" of Ninject as it's easier:
public class EfRepositoryModule : NinjectModule
{
public override void Load()
{
this.Bind<IProductRepository>().To<EfProductRepository>();
this.Bind<ExDbContext>().ToSelf().InRequestScope();
}
}
At first, we bind IProductRepository to our concrete implementation. Thereby, whenever a component needs a product repository, Ninject will create an instance of EfProductRepository and use that.
Then we tell Ninject to bind ExDbContext to itself and use the request scope. All dependencies on ExDbContext will be served by one single instance of this class during a request, and this instance is going to be disposed when the request ends.
Load the module. In App_Start/NinjectWebCommon.cs update the following method:
private static void RegisterServices(IKernel kernel)
{
kernel.Load<EfRepositoryModule>();
}
Add dependencies to your pages. In every page where you need to show products, add the following property:
[Inject]
public IProductRepository ProductRepository { get; set; }
We need to use property injection or method injection here, because Web Pages doesn't support constructor injection (which should usually be favored). The Inject attribute tells Ninject that we have a dependency here that we want to be injected.
Add a module for NHibernate later on.
public class NHibernateRepositoryModule : NinjectModule
{
public override void Load()
{
this.Bind<IProductRepository>().To<NHibernateProductRepository>();
// Bind whatever else you need when working with NHibernate
}
}
// NinjectWebCommon
private static void RegisterServices(IKernel kernel)
{
kernel.Load<EfRepositoryModule>();
}

ASP.Net MVC Constructor Injection with Autofac - Runtime parameters

I am reasonably new to Autofac and have come up against a problem when injecting dependencies that have arguments that are only known at runtime. (the code below is an example of the problem I am trying to describe).
Here is where I setup my container (which gets called in Global.asax)
public class Bootstrapper
{
public static void Config()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<PersonService>().As<IPersonService>().InstancePerHttpRequest();
builder.RegisterType<PersonRepository>().As<IPersonRepository>().InstancePerHttpRequest();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
Here are the types.
public class PersonService : IPersonService
{
private readonly IPersonRepository _repository;
public PersonService(IPersonRepository repository)
{
_repository = repository;
}
public Person GetPerson(int id)
{
return _repository.GetPerson(id);
}
}
public interface IPersonRepository
{
Person GetPerson(int id);
}
public class PersonRepository : IPersonRepository
{
private readonly int _serviceId;
public PersonRepository(int serviceId)
{
_serviceId = serviceId;
}
public Person GetPerson(int id)
{
throw new System.NotImplementedException();
}
}
Then the controller takes the PersonService in the constructor
public class HomeController : Controller
{
private readonly IPersonService _service;
public HomeController(IPersonService service)
{
_service = service;
}
public ActionResult Index()
{
return View();
}
}
Obviously this will fall over due to the container expecting the ServiceId argument on the constructor of PersonRepository with the following exception "Cannot resolve parameter 'Int32 serviceId'"
I can get the serviceId once I know HttpContext.Request.Current.Url, however this is not known at the time of creating the Container.
I have looked at many articles, forums etc but don't seem to be getting anywhere.
Could anyone point me in the right direction. Your help will be much appreciated.
Thanks
I know you use autofac but in our project we use Unity and it definitely can insert primitive types to type registration like this:
container.RegisterTypeWithParams<INewsRepository, NewsRepository>("ConnectionString", typeof(ILoggedUser));
Look at this
In general, you don't want to do this as you've modeled it (your PersonRepository). DI is used to resolve service dependencies, and what you have is a stateful component.
The way to model this is to use an abstract factory. Mark Seemann has an excellent blog post on this exact subject.
As you noted in your comment, passing the value via method injection is also an option, but can be ugly if it needs to be passed down through multiple dependencies.

Categories

Resources