I am getting "System.StackOverflowException was unhandled" on public
VolunteerDBEntities() : base("name=VolunteerDBEntities", "VolunteerDBEntities")
{
OnContextCreated();
}
It happens when I change this:
public class OrganizationService : IOrganizationService
{
private IValidationDictionary _validationDictionary;
private IOrganizationRepository _repository;
public OrganizationService(IValidationDictionary validationDictionary)
: this(validationDictionary, new OrganizationRepository())
{ }
public OrganizationService(IValidationDictionary validationDictionary, IOrganizationRepository repository)
{
_validationDictionary = validationDictionary;
_repository = repository;
}
...}
To this:
public class OrganizationService : IOrganizationService
{
private IValidationDictionary _validationDictionary;
private IOrganizationRepository _repository;
private ISessionService _session;
public OrganizationService(IValidationDictionary validationDictionary)
: this(validationDictionary, new OrganizationRepository(), new SessionService())
{ }
public OrganizationService(IValidationDictionary validationDictionary, IOrganizationRepository repository, ISessionService session)
{
_validationDictionary = validationDictionary;
_repository = repository;
_session = session;
}
...}
I'm clueless on this one. I set this up for unit testing and anytime I add a class variable to this service, it crashes. I can add a class variable to another services or create a service that replicates this minus the interface and it works. Any ideas?
Session Service Construct:
public class SessionService: ISessionService
{
private IMembershipService _membershipService;
private IVolunteerService _volunteerService;
private IMessageService _messageService;
public SessionService()
: this(new AccountMembershipService(null), new VolunteerService(null), new MessageService())
{}
public SessionService(IMembershipService membershipservice, IVolunteerService volunteerservice, IMessageService messageservice)
{
_membershipService = membershipservice;
_volunteerService = volunteerservice;
_messageService = messageservice;
}
Other Service Constructs:
private IValidationDictionary _validationDictionary;
private IVolunteerRepository _repository;
private IOrganizationService _orgservice;
public VolunteerService(IValidationDictionary validationDictionary)
: this(validationDictionary, new VolunteerRepository(), new OrganizationService(null))
{}
public VolunteerService(IValidationDictionary validationDictionary, IVolunteerRepository repository, IOrganizationService orgservice)
{
_validationDictionary = validationDictionary;
_repository = repository;
_orgservice = orgservice;
}
public class AccountMembershipService : IMembershipService
{
private readonly System.Web.Security.MembershipProvider _provider;
private IValidationDictionary _validationDictionary;
private IVolunteerService _volservice;
private IEmailService _emailservice;
public AccountMembershipService(IValidationDictionary validationDictionary)
: this(validationDictionary, null, new VolunteerService(null), new EmailService())
{
}
public AccountMembershipService(IValidationDictionary validationDictionary, System.Web.Security.MembershipProvider provider, VolunteerService volservice, EmailService emailservice )
{
_validationDictionary = validationDictionary;
_provider = provider ?? Membership.Provider;
_volservice = volservice;
_emailservice = emailservice;
}
You are creating the set of objects recursively.
Your code "smells" with test logic in production because you create all the objects implicitly.
Instead I would encourage to use dependency injection or other solutions so that you do not have hard dependencies in your constructors.
In the worst-case scenario, just use ServiceLocator pattern.
The last option is the easiest way to go for you as you already have too much stuff bound together. Your code would look like this:
public class OrganizationService : IOrganizationService
{
private IValidationDictionary _validationDictionary;
private IOrganizationRepository _repository;
public OrganizationService() {
_validationDictionary = ServiceLocator.Get<IValidationDictionary>();
_repository = ServiceLocator.Get<IOrganizationRepository>();
}
}
Let's look at the dependency on IOrganizationRepository here.
We don't need to know exact type of it. So we don't care. The ServiceLocator is the only body that does care.
Usually it is just a static class (keep in mind multi-threading and synchronization though!).
It can be implemented like this (I don't want to point to existing implementations because it is just too simple to do):
public static class ServiceLocator {
static Func<T, object> _resolver;
public static Setup(Func<T, object> resolver) {
_resolver = resolver;
}
public static TService Get<TService>() {
if (_resolver == null) throw InvalidOperationException("Please Setup first.");
return (TService)_resolver.Invoke(typeof(TService));
}
}
Then in your test setup (probably on the base test class) just do this:
ServiceLocator.Setup(what => {
if (what == typeof(IOrganizationRepository))
return organisationRepository = organisationRepository ?? new OrganizationRepository(); // Singleton
throw new NotSupportedException("The service cannot be resolved: " + what.Name);
});
In production you would instantiate it differently.
Of course it can be easier with CastleWindsor, Microsoft Unity or other dependency injection framework.
Hope that will help.
Related
I'm trying to create a general base class that I can use in my whole project. I've written some code but still getting a NULL instance on my DbConnectionFactory.
I've create a ASP.Net web api project and added the AppHost file. I'm using Funq together with Simple Injector to Injector my custom services into the Api Controllers.
AppHost.cs
public class AppHost : AppHostBase
{
public AppHost() : base("Erp", typeof(AppHostService).Assembly)
{
}
public override void Configure(Container container)
{
// init
var simpleInjectorContainer = new SimpleInjector.Container();
var erpConnection = ConnectionStrings.ErpLocal;
var isLocal = HelperTools.IsLocalPath();
// check
if (isLocal)
{
erpConnection = ConnectionStrings.ErpOnline;
}
// mvc
ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory(container));
// register funq services
container.Register<IErpDbConnectionFactory>(c => new ErpDbConnectionFactory(erpConnectionString));
container.RegisterAutoWiredAs<CategoryService, ICategoryService>();
container.RegisterAutoWiredAs<ManufacturerService, IManufacturerService >();
container.RegisterAutoWiredAs<ProductService, IProductService>();
container.RegisterAutoWiredAs<ProductAttributeService, IProductAttributeService>();
container.RegisterAutoWiredAs<SpecificationAttributeService, ISpecificationAttributeService>();
//...
// simple injector services
SimpleInjectorInitializer.Initialize(simpleInjectorContainer, isLocal);
// register SimpleInjector IoC container, so ServiceStack can use it
container.Adapter = new SimpleInjectorIocAdapter(simpleInjectorContainer);
}
}
Base Class I'm trying to use
public abstract class ApiOrmLiteController : ApiController
{
IDbConnection _erpDb;
public virtual IErpDbConnectionFactory ErpDbConnectionFactory { get; set; }
public virtual IDbConnection ErpDb => _erpDb ?? (_erpDb = ErpDbConnectionFactory.OpenDbConnection());
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_erpDb?.Dispose();
}
}
Web Api Controller
public class ShippingController : ApiOrmLiteController
{
#region Fields
private readonly IOrderService _orderService;
private readonly IAddressService _addressService;
private readonly ICustomerService _customerService;
private readonly IPdfService _pdfService;
private readonly IMessageService _messageService;
private readonly ITranslationService _translationService;
#endregion Fields
#region Ctor
public ShippingController(IOrderService orderService, IAddressService addressService, ICustomerService customerService, IPdfService pdfService, IMessageService messageService, ITranslationService translationService)
{
_orderService = orderService;
_addressService = addressService;
_customerService = customerService;
_pdfService = pdfService;
_messageService = messageService;
_translationService = translationService;
}
#endregion Ctor
[HttpGet]
[System.Web.Http.Route("Test")]
public void Test()
{
var products = ErpDb.Select<Category>();
}
}
You may need to use constructor injection for Web API or MVC controllers, alternatively you can access dependencies in ServiceStack's IOC via HostContext.TryResolve<T>, e.g:
public virtual IDbConnection ErpDb => _erpDb ??
(_erpDb = HostContext.TryResolve<IErpDbConnectionFactory>().OpenDbConnection());
I receive the following error while trying to inject one of my components:
No constructors on type 'Event.Function.Components.EventComponent' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'
As you can see, I am trying to inject the following components:
DependencyInjection.Initialize(builder =>
{
builder.RegisterType<DatabaseContext>().As<IDatabaseContext>()
.WithParameter("connectionString", ConfigurationManager.AppSettings["connectionString"].ToString());
builder.RegisterType<Repository>().As<IRepository>().SingleInstance().PropertiesAutowired();
builder.RegisterType<EventComponent>().As<IEventComponent>().SingleInstance().PropertiesAutowired();
builder.RegisterType<CommentComponent>().As<ICommentComponent>().SingleInstance().PropertiesAutowired();
}, functionName);
Below please find the class objects I am trying to inject.
public class DatabaseContext : DbContext, IDatabaseContext
{
public DatabaseContext(string connectionString) : base(connectionString)
{
}
}
public class Repository : IRepository
{
protected readonly IDatabaseContext Context;
public Repository(IDatabaseContext context)
{
Context = context;
}
}
public class EventComponent : IEventComponent
{
private readonly IRepository _repository;
private EventComponent(IRepository repo)
{
_repository = repo;
}
}
I am using .PropertiesAutoWired(), which gives the following definition, and according to my understanding, should know what IRepository is, since it is registered in the container.
Configure the component so that any properties whose types are registered in the container will be wired to instances of the appropriate service.
Am I doing something wrong?
Posting it here as it will hopefully help someone else, and maybe my future self.
After posting, I realized the constructor on my EventComponent is private, and it should be public.
So I changed:
public class EventComponent : IEventComponent
private readonly IRepository _repository;
private EventComponent(IRepository repo)
{
_repository = repo;
}
}
To:
public class EventComponent : IEventComponent
private readonly IRepository _repository;
public EventComponent(IRepository repo)
{
_repository = repo;
}
}
I'm developing multitenant application. I use separate databases for each tenant. UserData are for each tenant in separate database TOO.
My problem is how can i create admin account for each tenant in "custom" database independently on DI. In MVC 5 was possible to instantiate UserManager base on UserStore(connection string). But UserManager in mvc6 depends on HttpContext... No documentation found...
Exist please some way how to do it??? I need in mvc 6 something like this in mvc 5:
UserStore<TenantUser> store = new UserStore<TenantUser>(new TenantDbContext("CONNECTION STRING")); //!!! NO POSSIBLE CREATE USER IN CUSTOM DATABASE
UserManager<TenantUser> t = new UserManager<TenantUser>(store);
t.CreateAsync(user, password);
Update:
public class TenantDbContext : IdentityDbContext<TenantUser, TenantRole, Guid>
{
private string _connectionString { get; set; }
private readonly IHttpContextAccessor _contextAccessor;
private readonly ApplicationDbContext _applicationDbContext;
//THIS SUB UNCOMENT ONLY IF CREATE MIGRATIONS (dnx ef...)
/*
public TenantDbContext(DbContextOptions<TenantDbContext> options) : base(options)
{
this._connectionString = "CONNECTION STRING";
}
*/
public TenantDbContext(DbContextOptions<TenantDbContext> options, IHttpContextAccessor contextAccessor, ApplicationDbContext applicationDbContext) : base(options) {
_contextAccessor = contextAccessor;
_applicationDbContext = applicationDbContext;
TenantResolver resolver = new TenantResolver(_contextAccessor, _applicationDbContext);
string con = resolver.GetConnectionString();
if (con != string.Empty)
{
this._connectionString = con; }
else
{
this._connectionString = "CONNECTION STRING"; //Development connection string
}
}
public TenantDbContext() //Posibility to create TenantDbContext migration and development database with no connectionString in constructor
{
//this._connectionString = "CONNECTION STRING";
}
public TenantDbContext(string ConnectionString)
{
this._connectionString = ConnectionString;
}
public static TenantDbContext Create(string ConnectionString)
{
return new TenantDbContext(ConnectionString);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connectionString);
}
I hope that I correctly understand you. Let us we forget about the performance and the caching of multiple connections, which already opened to the databases. I suppose that you have multiple databases, which have the same schema. You need to access the databases using (sharing) the same database context.
I can suggest you two solutions.
The first solution consists from registering one context and reopening it if the one opened co change the connection string.
Let us you have TenantDbContext, which could be opened with different destination databases. For example with
#"Server=(localdb)\mssqllocaldb;Database=TenantDb1;Trusted_Connection=True;"
or
#"Server=(localdb)\mssqllocaldb;Database=TenantDb2;Trusted_Connection=True;"
First of all you remove OnConfiguring like
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlServer(#"Server=(localdb)\mssqllocaldb;Database=TenantDb;Trusted_Connection=True;");
}
which could exist in the definition of TenantDbContext and you use the following code in ConfigureServices of Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
var connection1 = #"Server=(localdb)\mssqllocaldb;Database=TenantDb1;Trusted_Connection=True;";
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<TenantDbContext>(options => options.UseSqlServer(connection1));
services.AddMvc();
...
}
In the way you inject TenantDbContext with one from the database (TenantDb1). Let us the TenantDbContext contains some entity set like Blog for example. Thus your can define some MVC controller in the following way
public class TenantsController : Controller
{
private TenantDbContext _context;
public TenantsController (TenantDbContext context)
{
_context = context;
}
public IActionResult Index() {
var con = _context.Database.GetDbConnection();
// now the con uses either TenantDb2 or TenantDb2
// con.ConnectionString can be used to get or set the
// connection string
string needConStr = #"Server=(localdb)\mssqllocaldb;Database=TenantDb2;Trusted_Connection=True;";
if (con.ConnectionString != needConStr) { // can be compared more carefully
_context.Database.CloseConnection();
con.ConnectionString = needConStr;
}
// get some data from the TenantDbContext
var blog = _context.Blog.ToList();
return View(blog);
}
}
The second solution don't need to inject any TenantDbContext using DependencyInjection. Instead of that you need just add one simple constructor to TenantDbContext:
public TenantDbContext(DbContextOptions optionsBuilder): base (optionsBuilder)
{
}
Such simple constructor will allows you to create the context at any time when you need it:
public class TenantsController : Controller
{
public IActionResult Index() {
var contextOptions = new DbContextOptionsBuilder();
contextOptions.UseSqlServer(#"Server=(localdb)\mssqllocaldb;Database=TenantDb2;Trusted_Connection=True;");
var context = new BloggingContext(contextOptions.Options);
context.Database.OpenConnection();
// get some data from the TenantDbContext
var blog = context.Blog.ToList();
return View(blog);
}
}
I used all the connection strings directly in the code. You can easy modify the above code to get all connection strings from the config file appsettings.json.
Solved.
1. CreateCustomUserStore
public class TenantUserStore : UserStore<TenantUser, TenantRole, TenantDbContext, Guid>
{
public TenantUserStore(TenantDbContext context, IdentityErrorDescriber describer = null): base(context, describer)
{
}
}
And here is code how to instantiate UserManager with custom database:
IUserStore<TenantUser> CustomStore = new TenantUserStore(new TenantDbContext(coonection), null);
UserManager<TenantUser> manager = new UserManager<TenantUser>(CustomStore, _optionsAccessor, _passwordHasher, _userValidators,
_passwordValidators, _keyNormalizer, _errors, _services, _logger, _contextAccessor);
And DI used only for rest of UserManager Constructor:
public class TenantsController : Controller
{
private readonly IHttpContextAccessor _contextAccessor;
private readonly IOptions<IdentityOptions> _optionsAccessor;
private readonly IPasswordHasher<TenantUser> _passwordHasher;
private readonly IEnumerable<IUserValidator<TenantUser>> _userValidators;
private readonly IEnumerable<IPasswordValidator<TenantUser>> _passwordValidators;
private readonly ILookupNormalizer _keyNormalizer;
private readonly IdentityErrorDescriber _errors;
private readonly IServiceProvider _services;
private readonly ILogger<UserManager<TenantUser>> _logger;
public TenantsController(IHttpContextAccessor contextAccessor,
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<TenantUser> passwordHasher,
IEnumerable<IUserValidator<TenantUser>> userValidators,
IEnumerable<IPasswordValidator<TenantUser>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IServiceProvider services,
ILogger<UserManager<TenantUser>> logger
)
{
_optionsAccessor = optionsAccessor;
_passwordHasher = passwordHasher;
_userValidators = userValidators;
_passwordValidators = passwordValidators;
_keyNormalizer = keyNormalizer;
_errors = errors;
_services = services;
_logger = logger;
_contextAccessor = contextAccessor;
}
I am having a project and my project is connecting to two different databases are BookStoreEntities and BlogEntities.
If I remove line code builder.RegisterType<BlogEntities>().As<DbContext>(); in Autofac configuration my project works fine and else I'll get error "The entity type Book is not part of the model for the current context".
My autofac config:
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<BookStoreEntities>().As<DbContext>();
builder.RegisterType<BlogEntities>().As<DbContext>();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerDependency();
builder.RegisterType<BookService>().As<IBookService>();
builder.RegisterFilterProvider();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
Repository class:
public class Repository<T> : IRepository<T> where T : class
{
private DbContext _dbContext;
private DbSet<T> _dbSet;
public Repository(DbContext dbContext)
{
_dbContext = dbContext;
_dbSet = dbContext.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _dbSet;
}
}
Service layer:
public class BookService : IBookService
{
private IRepository<Book> _bookRepository;
public BookService(IRepository<Book> bookRepository)
{
_bookRepository = bookRepository;
}
public IEnumerable<Book> GetBooks()
{
return _bookRepository.GetAll();
}
}
Controller:
public class BookController : Controller
{
private IBookService _bookService;
public BookController(IBookService bookService)
{
_bookService = bookService;
}
// GET: Book
public ActionResult Index()
{
var books = _bookService.GetBooks();
return View(books);
}
}
My Project is using 2 different databases and Service layer will implement from this Generic Repository. I want to myservice1 works with MyDbContext1 and myservice2 works with MyDbContext2
Then don't new your DbContext inside your repository. That makes testing hard anyway.
Inject it:
public Repository(DbContext dbContext)
{
_dbContext = dbContext;
}
Now the repository doesn't care which DbContext-derived class is injected. This works because you only call DbContext.Set<T>().
Try to something like:
public class MyDbContext1 : DbContext
{
public MyDbContext1 ()
:base("ConnectionString")
{ }
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//...
}
}
And add to repository new property
private IDbSet<T> Entities
{
get
{
if (_dbSet == null)
{
_dbSet = _dbContext1.Set<T>();
}
return _dbSet;
}
}
I am learning how to use nInject for a new application I am developing, and I have created the following sample code that can be copied/pasted into a simple console app. It successfully returns an instance of IFoo, but I have a question about it.
How would I modify the code to have the FooManager class create an instance of the Foo object without doing a 'new'. Does the kernal have to be injected as well? But if the kernal is injected and I change the line to read var foo = _kernel.Get<IFoo>(), isn't that introducing a service locator anti-pattern?
namespace IOCTest
{
class Program
{
static void Main(string[] args)
{
using (IKernel kernel = new StandardKernel(new StandardModule()))
{
// do something with the kernal
var mgr = kernel.Get<IFooManager>();
var foo = mgr.GetById(1);
}
}
}
public class StandardModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
Bind<IDatabase>()
.To<Database>()
.InTransientScope();
Bind<IFooManager>()
.To<FooManager>()
.InTransientScope();
}
}
//******************************************************
public interface IDatabase
{
object[] GetScalar(int id);
}
public class Database : IDatabase
{
public object[] GetScalar(int id)
{
return new object[] { "RowName" };
}
}
//******************************************************
public interface IFooManager
{
IFoo GetById(int id);
}
public class FooManager : IFooManager
{
private IDatabase _db;
public FooManager(IDatabase db) { _db = db; }
public IFoo GetById(int id)
{
var results = _db.GetScalar(id);
var foo = new Foo(); // <-- HOW DO I ELIMINATE THIS DEPENDENCY?
foo.Name = results[0].ToString();
return foo;
}
}
//******************************************************
public interface IFoo
{
string Name { get; set; }
}
public class Foo : IFoo
{
public string Name { get; set; }
}
//******************************************************
}
First you have to think about the purpose of Foo. Is this some kind of a datacontainer or some service?
In the first case your code is perfect like it is. Datacontainers have no dependencies and shouldn't be created by the IoC container.
In the second case read about Ninject.Extensions.Factory.
http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/
https://github.com/ninject/ninject.extensions.factory/wiki
There are a couple ways to eliminate that dependency. You could do the same thing you did with the Database dependency and use constructor injection. You could do property injection (https://github.com/ninject/ninject/wiki/Injection-Patterns). Another way, and perhaps what you are looking for, would be service location. To do that you can update your FooManager ctor to require an IKernel. This will be resolved automatically and you can then use the kernel that is passed in to get Foo.
public class FooManager : IFooManager
{
private IDatabase _db;
private IKernel _kernel;
public FooManager(IDatabase db, IKernel kernel) { _db = db; _kernel = kernel;}
public IFoo GetById(int id)
{
var results = _db.GetScalar(id);
// var foo = new Foo(); // <-- HOW DO I ELIMINATE THIS DEPENDENCY?
var foo = kernel.Get<IFoo>(); // Like this perhaps
foo.Name = results[0].ToString();
return foo;
}
}