Last post Dec 28, 2020 11:28 PM by PatriceSc
Dec 28, 2020 02:18 PM|kobruleht|LINK
Postgres database has multiple schemes like company1, company2, ... companyN
Browser sends cookie containing scheme name . Data access operations should occur in this scheme. Web application user can select different scheme. In this case different cookie value is set.
Npgsql EF Core Data provider is used.
ASP NET MVC 5 Core application registers factory in StartUp.cs :
public void ConfigureServices(IServiceCollection services)
Home controller tries to use it:
public class HomeController : EevaController
public ActionResult Index()
var sm = new SchemeManager();
This throws exception since factory member is null. How to fix this ?
public interface IEevaContextFactory
public class EevaContextFactory : IEevaContextFactory
private IHttpContextAccessor httpContextAccessor;
private IConfiguration configuration;
public EevaContextFactory(IHttpContextAccessor httpContextAccessor, IConfiguration configuration)
this.httpContextAccessor = httpContextAccessor;
this.configuration = configuration;
public EevaContext Create()
var builder = new DbContextOptionsBuilder<EevaContext>();
var pathbase = httpContextAccessor.HttpContext.Request.PathBase.Value;
var scheme = httpContextAccessor.HttpContext.Request.Cookies["Scheme"];
var csb = new NpgsqlConnectionStringBuilder()
Host = pathbase,
SearchPath = scheme
return new EevaContext(builder.Options);
Scheme data acess methods:
public class SchemeManager
readonly IEevaContextFactory factory;
public SchemeManager(IEevaContextFactory factory)
this.factory = factory;
public void PerformInsert()
using (var context = factory.Create())
var commandText = "INSERT into maksetin(maksetin) VALUES (CategoryName)";
Dec 28, 2020 02:39 PM|mgebhard|LINK
The problem is you are not following standard ASP.NET Core dependency injection fundamentals. Services are injected through the constructor. You are manually "newing" the SchemeManager which invokes the parameterless constructor.
I recommend reading the official dependency reference docs and maybe take a look at the C# programming guide to understand how constructors work.
Dec 28, 2020 02:52 PM|PatriceSc|LINK
Seems expected as you are using explicitely the SchemeManager constructor that doesn't provide the needed dependency.
Don't you inject IEevaContextFactory in your controller that you could then pass to SchemeManager. A step further would be to register and inject SchemeManager as well.
Dependency injection resolves the whole graph ie if you register a class A needed to create a class B needed to create a class C, when you'll inject class C, DI will walk through those dependencies and will create A, B from A and C from B to give you back
what you asked for.
Dec 28, 2020 03:53 PM|kobruleht|LINK
In real application controller calls other method, other method calls other etc. Database access occurs only at at nth nesting level.
Using your hint requires adding factory parameter to large number of methods.
How to avoid this ?
In .NET 4.8 ˇHttpContext.Currentˇ can used but it does not exist in .NET 5.
How to use Dependenvy injection or other method for this ?
Dec 28, 2020 05:57 PM|PatriceSc|LINK
Seems to me you have all in place ie you could:
1) delete the parameterless SchemeManager constructor so that you can't create a class you can't use anyway
2) add services.AddScoped<SchemeManager>(); to available services
3) then rather than creating the SchemeManager yourself you can use
private readonly SchemeManager _scheme;
public HomeController(SchemeManager scheme)
_scheme = scheme;
and so this class (and all on which it depends) is created for you
Dec 28, 2020 06:33 PM|kobruleht|LINK
It loks that dependecy injection and factory pattern do not have any additional value in this case.
It looks like most reasonable is to pass controller HttpContext property to every data-access method called from controller and not use DI and factory patterns?
Or is it more reasonable to pass Cookie and PathBase values from HttpContext.Request as strings to avoid HttpContext become null in async methods ?
Dec 28, 2020 11:28 PM|PatriceSc|LINK
Yes, if you pass or use the HttpContext directly then a current http request is required which can be a problem if you later want to write tests, have to create a console job or a dekstop admin app, allow an admin to select another tenant/schema than the
"current" one or just want to change your mind about which source within the HttpContext is used (and make sure it is changed everywhere it is needed).
If instead you pass just the needed information as strings you'll avoid to take that dependency and will add the flexibility to eaésily pass whatever best fit.
DI is a bit similar. If class B is used directly by multiple classes, this coupling could be changed only by doing mutliple code changes. If instead you are using DI a single change is enough to test a newer or another version etc... Keep this in mind to
see over time if you don't find your own use cases where DI would have been easier.
Edit: BTW your WebMatrix issue could be a quite good use case. It depends directly on the old configuration system while ASP.NET Core uses IConfiguration which allows to get the config from any source you want (even not yet existing). A bit late here but
if starting from the very beginning, it seems you are doing anyway nothing else than changing the connection string based on the current http request? I would have to try but UsenpgSql might allow that already (I believe I have seen that for SQL Server).