C# - Change DbContext ConnectionString after Auth - c#

I'm trying to make an application that changes the DbConnection string based on the authenticated user.
So, after the user login, I have to get that user, see a field like "connectionName" and look for that connectionString on my app.config to connect to my database.
I already know how to set my Dependency Injection to pass the constructor params, but how do I get at my dependency injector Project the logged user ?
Something like this.
This is in a Project called "Project.Infra"
DBContext
public class MyDbContext : DbContext
{
//ConnectionStringBasedOnUserLogged will be a propertie on my userModel
//so I have to get the logged user before have it.
public MyDbContext(string ConnectionStringBasedOnUserLogged)
: base(ConnectionStringBasedOnUserLogged)
{
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
}
//DbSets...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Mappings...
}
}
This is in a Project called "Project.Infra"
Repository
public class MyRepository : IMyRepository
{
private MyDbContext _ctx;
public MyRepository(MyDbContextcontext)
{
this._ctx = context;
}
//Implementation of interface...
}
This is in a Project called "Project.Api"
Controller
public class MyController : ApiController
{
private IMyRepository _repo;
public MyController(IMyRepository repo)
{
this._repo = repo;
}
//Implementation
}
This is in a Project called "Project.Startup"´
DepencyInjection
public static class DependencyResolver
{
public static void Resolve(UnityContainer container)
{
//How do I get here some details about the logged user at my application ?
container.RegisterType<MyDbContext, MyDbContext>(new HierarchicalLifetimeManager(), new InjectionConstructor("HereWillComeTheConnection"));
container.RegisterType<IMyRepository, MyRepository>(new HierarchicalLifetimeManager()); }
}

Related

How to use Dependency inject when using a service layer with Entity Framework Core?

My project is an ASP.NET Core 6 Web API. I am using Entity Framework Core and built-in dependency injection.
Program.cs:
var builder = WebApplication.CreateBuilder(args);
...
builder.Services.AddDbContext<myService>(options => options.UseSqlServer(ConnStr));
builder.Services.AddDbContext<anotherService>(options => options.UseSqlServer(anotherConnStr));
...
myController.cs:
public class myController : ControllerBase
{
private readonly myService _context;
public myController(myService context)
{
_context = context;
}
// ... Routes use either db models directly or methods from myService
}
myService.cs:
I'm using myContext as a base class so I can access the db tables directly in my controller.
Any better way to do this? db = this;
How do I inject this service?
private readonly anotherService anotherdb;
public class myService : myContext
{
private readonly myContext db;
private readonly anotherService anotherdb;
public myService(DbContextOptions<myService> options) : base(options)
{
// inject myContext, works but doesn't feel right.
db = this;
// how do I inject this?
anotherdb = new anotherService();
}
public IQueryable<mytable> Getdata()
{
var q = from s in db.mytable
select s;
return q;
}
// ...
}
myContext.cs:
public partial class myContext : DbContext
{
public myContext()
{
}
public myContext(DbContextOptions<myContext> options)
: base(options)
{
}
protected myContext(DbContextOptions options)
: base(options)
{
}
// ...
}
I have lots of services all with the same design, how can I inject another service into myService.cs?

How to register a class to IoC in Prism

I write an application with WPF. I use the Prism library with IoC as Prism.DryIoC.
I have an AppDbContext.cs class to declare the connection string to the database (here is MongoDB)
public class AppDbContext : BaseMongoRepository
{
public AppDbContext(string connectionString, string databaseName = null) : base(connectionString, databaseName)
{
}
}
I have a class MyService.cs that uses the AppDbContext class, I declare in the constructor.
public class MyService : IMyService
{
private AppDbContext _dbContext;
public IdentifierRepository(AppDbContext dbContext)
{
_dbContext = dbContext;
}
public void AddCustomer(Customer model)
{
// Some code....
_dbContext.Add(model);
}
}
In the App.xaml.cs class I override the method
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IAuthenticationService, AuthenticationService>();
// MongoDB
var connectionString = SharedCommon.LocalAppSettings.Database.ConnectionString;
var database = SharedCommon.LocalAppSettings.Database.DatabaseName;
// How to register class MyService.cs here?
// I dont known.
containerRegistry<MyService>(() => new MyService(new AppDbContext(connectionString, database))); // Wrong code
}
You can find all the registration methods here.
For singleton MyService:
var myService = new MyService(new AppDbContext(connectionString, database)));
containerRegistry.RegisterInstance(myService);
For multiple instances you could use a factory instead.
public class MyServiceFactory
{
private readonly AppDbContext appDbContext;
public MyServiceFactory(AppDbContext appDbContext)
{
this.appDbContext = appDbContext;
}
public MyService Create() => new MyService(appDbContext);
}
Register the instance of the factory:
var context = new AppDbContext(connectionString, database);
var factory = new MyServiceFactory(context);
containerRegistry.RegisterInstance(factory);
Then create your service instance:
var factory = container.Resolve<MyServiceFactory>();
var service = factory.Create();

show Method name expected when using StructureMap

i using StructureMap in my project for using DepencyInjection . I have 5 project in my solution.
I have IUnitOfWork interface in DAL and I Defnation Function of IUnitOfWork in ApplicationDbContext .
ApplicationDbContext :
public class ApplicationDbContext : DbContext, IUnitOfWork
{
public ApplicationDbContext()
: base("ApplicationDBContext")
{
}
public virtual DbSet<User> Users { get; set; }
public void ForceDatabaseInitialize()
{
Database.Initialize(true);
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
#region IUnitOfWork Members
public void MarkAsDeleted<TEntity>(TEntity entity) where TEntity : class
{
Entry(entity).State = EntityState.Deleted;
}
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
.
.
.
now when I want to register IUnitOfWork in main project :
public static class StructureMapDefnation
{
private static readonly Lazy<Container> _containerBuilder =
new Lazy<Container>(defaultContainer, LazyThreadSafetyMode.ExecutionAndPublication);
public static IContainer Container
{
get { return _containerBuilder.Value; }
}
private static Container defaultContainer()
{
var container = new Container(ioc =>
{
// map same interface to different concrete classes
ioc.For<IUser>().Use<EfUserService>();
ioc.For<IUnitOfWork>().Use(() => new ApplicationDbContext())();
});
container.AssertConfigurationIsValid();
return container;
}
}
it show me this error :
Severity Code Description Project File Line Suppression State
Error CS0149 Method name expected BimehKosarFinal E:\myproject\BimehKosarFinal\BimehKosarFinal\StructureMap\StructureMapDefnation.cs 28 Active
in this line :
ioc.For<IUnitOfWork>().Use(() => new ApplicationDbContext())();
whats the problem ? how can I solve this problem ?
remove the last (), and write
ioc.For<IUnitOfWork>().Use(() => new ApplicationDbContext());
Or
ioc.For<IUnitOfWork>().Use<ApplicationDbContext>();

Using inheritance and dependency injection at the same time

Here is how my application makes a call to the database:
Web App -> Business Layer -> Data Layer
Everything is using dependency injection.
For example:
In the controller in my Web app I make a call like this:
await _manager.GetCustomers();
Which goes into my Business Layer:
public class CustomerManager : ICustomerManager
{
private ICustomerRepo _repository;
public CustomerManager(ICustomerRepo repository)
{
_repository = repository;
}
public Task<IList<Customer>> GetCustomers(string name = null)
{
return _repository.GetCustomers(name);
}
}
Which goes into my Data Layer:
public class CustomerRepo : BaseRepo, ICustomerRepo
{
public CustomerRepo(IConfigurationRoot configRoot)
: base(configRoot)
{
}
public Customer Find(int id)
{
using (var connection = GetOpenConnection())
{
...
}
}
}
The trick here is that CustomerRepo inherits from BaseRepo to be able to use the GetOpenConnection() function. But at the same time BaseRepo needs an IConfigurationRoot injected into it from the web application. How can I do both?
public class BaseRepo
{
private readonly IConfigurationRoot config;
public BaseRepo(IConfigurationRoot config)
{
this.config = config;
}
public SqlConnection GetOpenConnection(bool mars = false)
{
string cs = config.GetSection("Data:DefaultConnection:ConnectionString").ToString();
...
}
}
How would you instantiate (or even compile) a CustomerRepo at all, regardless of dependency injection? You need an IConfigurationRoot parameter to pass through to the base constructor. Like:
public CustomerRepo(IConfigurationRoot configRoot)
: base(configRoot)
{
}
See https://msdn.microsoft.com/en-us/library/hfw7t1ce.aspx for info on the base keyword.

Can I get WebApi to work with IoC Aspects/Interceptor

I'm from a WCF background where I successfully used IoC with Aspects/Interceptors to abstract functions such as Authentication and Logging. I would simply just add the required interfaces to the aspects constructor the same way as you would with any typical IoC setup.
I'm now trying to apply the same sort of process to webapi, but as the controllers inherit from a ApiController and do not implement a interface. I'm assuming there is a different way of applying aspects maybe?
public class MyController: ApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly ILoginService _loginService;
private readonly ILog _log;
public LoginController(ILoginService loginService, IUnitOfWork unitOfWork, ILog log)
{
this._loginService = loginService;
this._unitOfWork = unitOfWork;
this._log = log;
}
// I WANT TO INTERCEPT THIS METHOD USING UserTokenAuthenticationInterceptor
public HttpResponseMessage Get(Guid id)
{
_log.Log(log something);
// some code thats gets some data using this._loginService
_log.Log(log the save);
_unitOfWork.Save();
}
}
The Aspect
public class UserTokenAuthenticationInterceptor : IInterceptionBehavior
{
private readonly ILoginService _loginService;
private readonly ILog _log;
public UserTokenAuthenticationInterceptor(ILog log, ILoginService loginService)
{
this._log = log;
this._loginService = loginService;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
_log.Log(log entering authentication aspect);
// do some authentication here using this._loginService
_log.Log(log exiting authentication aspect);
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public bool WillExecute { get { return true; }}
}
Container registration:
container.RegisterType<IUnitOfWork, UnitOfWork.UnitOfWork>(new HierarchicalLifetimeManager());
container.RegisterType<ILoginService , LoginService>();
container.RegisterType<ILog, LogService>();
I'm using unity in this example.
Can anyone point me in the right direction?
Thanks for the help everyone, I eventually figured it out.
I got most of my answer from this article https://unity.codeplex.com/discussions/446780
I used the the following nuget packages.
Unity (I added this 1 first)
Unity.WebApi (has unity version problem if unity isnt added first)
First I needed a new IFilterProvider implementation.
Its job it to register all actionfilters with the container.
public class UnityActionFilterProvider : ActionDescriptorFilterProvider, IFilterProvider
{
private readonly IUnityContainer container;
public UnityActionFilterProvider(IUnityContainer container)
{
this.container = container;
}
public new IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
{
var filters = base.GetFilters(configuration, actionDescriptor);
foreach (var filter in filters)
{
container.BuildUp(filter.Instance.GetType(), filter.Instance);
}
return filters;
}
}
Then a registration method was required to register the new actionfilterprovider and remove the original webapi implementation.
This needs to be executed in the RegisterComponents() method which is in the UnityConfig.cs file the Unity.WebApi nuget package creates.
public static void RegisterFilterProviders(IUnityContainer container)
{
var providers = GlobalConfiguration.Configuration.Services.GetFilterProviders().ToList();
GlobalConfiguration.Configuration.Services.Add(typeof(System.Web.Http.Filters.IFilterProvider),
new UnityActionFilterProvider(container));
var defaultprovider = providers.First(p => p is ActionDescriptorFilterProvider);
GlobalConfiguration.Configuration.Services.Remove(typeof(System.Web.Http.Filters.IFilterProvider), defaultprovider);
}
In the same RegisterComponents() method I registered my Types
container.RegisterType<IUnitOfWork, UnitOfWork.UnitOfWork>(new HierarchicalLifetimeManager());
container.RegisterType<ILoginService , LoginService>();
container.RegisterType<ILog, LogService>();
Next, I needed to create a class based on AuthorizeAttribute.
public class UserTokenAuthenticationAttribute : AuthorizeAttribute
{
private ILoginService _loginService;
// This is the magic part - Unity reads this attribute and sets injects the related property. This means no parameters are required in the constructor.
[Microsoft.Practices.Unity.Dependency]
public ILoginService LoginService
{
get
{
return this._loginService;
}
set
{
this._loginService = value;
}
}
protected override bool IsAuthorized(HttpActionContext actionContext)
{
// Authorise code goes here using injected this._loginService
}
}
A log action filter is also required ActionFilterAttribute
public sealed class LogAttribute : ActionFilterAttribute
{
private ILog _log;
// This is the magic part - Unity reads this attribute and sets injects the related property. This means no parameters are required in the constructor.
[Microsoft.Practices.Unity.Dependency]
public ILog Log
{
get
{
return this._log;
}
set
{
this._log = value;
}
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
this._log.Info("Exited " + actionContext.Request.Method);
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
this._log.Info("Entering" + actionContext.Request.Method);
}
}
Now lets configure the webapi controller. We need to decorate the class with our new attributes
[UserTokenAuthentication] // magic attribute in use
[Log] // magic attribute in use
public class MyController: ApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly ILoginService _loginService;
private readonly ILog _log;
public MyController(ILoginService loginService, IUnitOfWork unitOfWork, ILog log)
{
this._loginService = loginService;
this._unitOfWork = unitOfWork;
this._log = log;
}
[System.Web.Http.AllowAnonymous] // doesnt require authentication as were not logged in yet
public HttpResponseMessage Get(Guid id)
{
_log.Log(log something);
// some code thats gets some data using this._loginService
_log.Log(log the save);
_unitOfWork.Save();
}
public HttpResponseMessage GetMyDetails(Guid id)
{
_log.Log(log something);
// some code thats gets some data using this._loginService
_log.Log(log the save);
_unitOfWork.Save();
}
}
I'm an Autofac guy myself, but according to this blog post the same thing can be done in Unity: You hand over controller instantiation to your IoC container and then you can use dependency injection in the controllers.
This being said, I've never worked with interceptors so I'm not sure how these can be registered to work properly. And it seems that the IInterceptionBehavior is obsolete in Unity and no longer maintained.
In WebApi, you can create an ActionFilter which can be called before and after a controller action is invoked:
public sealed class UserTokenAuthenticationAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
...
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
...
}
}
There are different types of filter available depending on what you need do do for example AuthorizationFilterAttribute and ExceptionFilterAttribute.
You can register a single instance of this in GlobalConfiguration.Configuration.Filters.Add(new UserTokenAuthenticationAttribute ()) if you want it to apply for all controller actions, or you can apply it to an individual controller or action if you need more flexibility about when that action filter is used.
By default, action filters are not resolved from an IOC container, they are essentially created by Activator.CreateInstance.
I'm not sure if it is possible in Unity as I've never used it but Autofac can resolve action filters if configured to do so using the RegisterWebApiFilterProvider method in the Autofac WebApi extension.
Better write your custom AuthorizeAttribute implementation. Example:
public class ApiAuthorizeAttribute : AuthorizeAttribute{
protected override bool IsAuthorized(HttpActionContext actionContext){
// Make your logic to check is user authorized
}
public override void OnAuthorization(HttpActionContext actionContext){
// Make your authorization logic
}
}
Then use it for all your ApiController's
[ApiAuthorize]
public class MyController: ApiController{
private readonly IUnitOfWork _unitOfWork;
private readonly ILoginService _loginService;
private readonly ILog _log;
// That method don't need authorization
[AllowAnonymous]
public LoginController(ILoginService loginService, IUnitOfWork unitOfWork, ILog log)
{
this._loginService = loginService;
this._unitOfWork = unitOfWork;
this._log = log;
}
// Before calling that method will be called logic from `ApiAuthorizeAttribute`
public HttpResponseMessage Get(Guid id)
{
_log.Log(log something);
// some code thats gets some data using this._loginService
_log.Log(log the save);
_unitOfWork.Save();
}
}
It will work the same as Aspect(actualy it is an Aspect but in ASP.NET MVC way) except that you will work with HttpActionContext(more hight level model, which will help you to achive the same but in the faster way. Also you will able to manipulate with HTTP headers) instead of working with low-level IInvocation.

Categories

Resources