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());
Related
We have a ASP.NET project, and we use AutoFac to DI.
We have a Service layer with all database queries and we need to make some queries in a static class.
This is how we register the dependencies in the Global.asax:
public class Dependencies
{
public static void RegisterDependencies()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
builder.RegisterModule(new ServiceModule());
builder.RegisterModule(new EfModule());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
public class ServiceModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(Assembly.Load("MyApp.Service")).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();
}
}
public class EfModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType(typeof(myDataContext)).As(typeof(IMyContext)).InstancePerLifetimeScope();
}
}
And this is how we access in the controller:
public class SomeController : Controller
{
private readonly IService1 _service1;
private readonly IService2 _service2;
public SomeController(IService1 service1, IService2 service2)
{
_service1 = service1;
_service2 = service2;
}
public ActionResult Index()
{
var service = _service1.GetAll();
...
return View(searchModel);
}
}
Now we need to retrieve data from the database in a static class, so we have to call our service layer, but we don't know how to do it...we have seen this, but I don't know if it is correct, but it works.
public static Test ()
{
...
var service1 = DependencyResolver.Current.GetService<IService1>();
...
}
Also, how it would be in both, non-static and static classes?
Thanks in advance.
The problem is I have to call many of those classes from different places and I don't want to depend on having the service in order to call the class, I'd like the class to take care of everything.
In this case you should register your class with Autofac so that it gets its dependencies injected:
builder.RegisterType<MyClass>();
If the class is used several times during a single request it might be useful to register it using InstancePerLifetimeScope(), but that depends on your overall architecture. See this link to the Autofac documentation for more information.
Of course you have to change your class so that the methods are not static any more and add an constructor to get the dependencies:
public class MyClass
{
private readonly IService1 _service1;
public MyClass(IService1 service1)
{
_service1 = service1;
}
public void Test
{
// use the _service1 instance to do whatever you want
}
}
Now you can inject the MyClass dependency in your controller and use it without having to know anything about its internals or its dependencies:
public class SomeController : Controller
{
private readonly IService1 _service1;
private readonly IService2 _service2;
private readonly MyClass _myClass;
public SomeController(IService1 service1, IService2 service2, MyClass myClass)
{
_service1 = service1;
_service2 = service2;
_myClass = myClass;
}
public ActionResult Index()
{
var service = _service1.GetAll();
...
_myClass.Test();
return View(searchModel);
}
}
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 have WebApi project with ODataController and I'm trying to inject some dependency into MyController. I was following this blogpost by Mark Seemann.
Consider code below.
Problem is, that when is MyController creating, I got exception inside WindsorCompositionRoot Create method on this line,
var controller = (IHttpController)this.container.Resolve(controllerType);
An exception of type 'Castle.MicroKernel.ComponentNotFoundException'
occurred in Castle.Windsor.dll but was not handled in user code
Additional information: No component for supporting the service
System.Web.OData.MetadataController was found
Any idea how to fix this?
Thank you.
My controller:
public class MyController : ODataController
{
private readonly DataLayer _db;
public PrepravyController(DataLayer db)
{
_db = db;
}
}
CompositonRoot:
public class WindsorCompositionRoot : IHttpControllerActivator
{
private readonly IWindsorContainer container;
public WindsorCompositionRoot(IWindsorContainer container)
{
this.container = container;
}
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
var controller =
(IHttpController)this.container.Resolve(controllerType);
request.RegisterForDispose(
new Release(
() => this.container.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action release;
public Release(Action release)
{
this.release = release;
}
public void Dispose()
{
this.release();
}
}
}
Global asax:
var container = new WindsorContainer();
container.Install(new RepositoriesInstaller());
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorCompositionRoot(container));
GlobalConfiguration.Configure(WebApiConfig.Register);
Make sure you're registering all your controllers with the container:
public class ControllerInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<IController>().LifestylePerWebRequest())
.Register(Classes.FromThisAssembly().BasedOn<ApiController>().LifestylePerWebRequest());
}
}
Windsor uses installers to encapsulate and partition registration logic. It also includes a helper called FromAssembly, so you don't need to manually instantiate all your installers:
_container = new WindsorContainer();
_container.Install(FromAssembly.This());
I am able to register FluentValidation AbstractValidators using a FluentValidatorFactory. However, it doesn't feel right, because not all of the IoC container registrations happen during bootstrap / composition root. Instead, the fluent validators are registered by a separate factory:
The composition root:
public class SimpleDependencyInjector : IServiceProvider
{
public readonly Container Container;
public SimpleDependencyInjector()
{
Container = Bootstrap();
}
internal Container Bootstrap()
{
var container = new Container();
container.Register< // ...register all non-fluent-validator types, then
container.Verify();
return container;
}
public object GetService(Type serviceType)
{
return ((IServiceProvider)Container).GetService(serviceType);
}
}
An abstract fluent validator factory depending only on IServiceProvider
public abstract class FluentValidatorFactory : ValidatorFactoryBase
{
private IServiceProvider Injector { get; set; }
protected FluentValidatorFactory(IServiceProvider injector)
{
Injector = injector;
}
public override IValidator CreateInstance(Type validatorType)
{
return Injector.GetService(validatorType) as IValidator;
}
}
A fluent validator factory implementation for SimpleInjector
public class SimpleValidatorFactory : FluentValidatorFactory
{
public SimpleValidatorFactory(SimpleDependencyInjector injector)
: base(injector)
{
var validators = AssemblyScanner.FindValidatorsInAssembly(
Assembly.GetCallingAssembly());
validators.ForEach(validator =>
injector.Container.Register(
validator.InterfaceType, validator.ValidatorType));
injector.Container.Verify();
}
}
SimpleInjector has good support for open generics, and all of my fluent validator classes have signatures similar to the following:
public class SomeClassValidator : AbstractValidator<SomeClass>
{
public SomeClassValidator([depedencies injected here])
{
// ... set up validation rules
}
}
So, is there a better way to register the validators in the bootstrap / composition root, instead of using fluent's validator factory?
P.S. #DotNetJunkie -- would be great if you had a wiki page on this at simpleinjector.codeplex.com.
I think I figured this out myself.
1.) Register fluent's open generic IValidator<T> interface in the composition root:
public class SimpleDependencyInjector : IServiceProvider
{
public readonly Container Container;
public SimpleDependencyInjector()
{
Container = Bootstrap();
}
internal Container Bootstrap()
{
var container = new Container();
// some container registrations
var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
container.RegisterManyForOpenGeneric(typeof(IValidator<>), assemblies);
// some more registrations
container.Verify();
return container;
}
public object GetService(Type serviceType)
{
return ((IServiceProvider)Container).GetService(serviceType);
}
}
2.) Get rid of the SimpleValidatorFactory class.
3.) Make the FluentValidatorFactory a non-abstract, concrete class:
public class FluentValidatorFactory : ValidatorFactoryBase
{
private IServiceProvider Injector { get; set; }
public FluentValidatorFactory(IServiceProvider injector)
{
Injector = injector;
}
public override IValidator CreateInstance(Type validatorType)
{
return Injector.GetService(validatorType) as IValidator;
}
}
4.) Register the FluentValidatorFactory as the validation factory provider in global.asax:
var injector = new SimpleDependencyInjector();
FluentValidationModelValidatorProvider.Configure(
provider =>
{
provider.ValidatorFactory = new FluentValidatorFactory(injector);
}
);
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.