I implemented OAuthAuthorizationServerProvider. I inject IOAuthService (my service for authentication) to implementation of OAuthAuthorizationServerProvider.
Implementation of IOAuthService gives DbContext through parameter of contructor. So, OAuthAuthorizationServerProvider gives DbContext as a singleton.
How can I inject DbContext to my implementation OAuthAuthorizationServerProvider using Autofac with per web request scope?
If I try to register dbcontext using following code:
builder.RegisterType<OAuthProviderContext>().As<DbContext>().InstancePerWebRequest();
then I will get an error: new scope could not be associated with HttpRequest.
public class ADAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
private readonly IAppSettings _appSettingsProvider;
private readonly IOAuthServiceProvider _oauthServiceProvider;
public ADAuthorizationServerProvider(IAppSettings appSettingsProvider,
IOAuthServiceProvider oauthServiceProvider)
{
_appSettingsProvider = appSettingsProvider;
_oauthServiceProvider = oauthServiceProvider;
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
//code
}
public class OAuthServiceProvider : IOAuthServiceProvider
{
private readonly IRefreshTokenRepository _refreshTokenRepository;
private readonly IClientRepository _clientRepository;
private readonly IUserRepository _userRepository;
private readonly IUnitOfWork _unitOfWork;
public OAuthServiceProvider(IRefreshTokenRepository refreshTokenRepository,
IClientRepository clientRepository,
IUserRepository userRepository,
IUnitOfWork unitOfWork)
{
_refreshTokenRepository = refreshTokenRepository;
_clientRepository = clientRepository;
_userRepository = userRepository;
_unitOfWork = unitOfWork;
}
public async Task AddRefreshToken(RefreshToken token)
{
//code...
}
public async Task DeleteRefreshToken(string tokenId)
{
//code...
}
public async Task<Client> FindClient(string clientName)
{
//code...
}
public async Task<RefreshToken> FindRefreshToken(string tokenId)
{
//code...
}
public async Task<User> FindUser(string username)
{
//code...
}
}
public class ClientRepository : BaseReadonlyRepository<Guid, Client>, IClientRepository
{
public ClientRepository(DbContext dbContext) : base(dbContext)
{
}
public async Task<Client> GetByName(string name)
{
//code...
}
}
public class RefreshTokenRepository : BaseRepository<string, RefreshToken>, IRefreshTokenRepository
{
public RefreshTokenRepository(DbContext dbContext) : base(dbContext)
{
}
}
public class UserRepository : BaseReadonlyRepository<Guid, User>, IUserRepository
{
public UserRepository(DbContext dbContext) : base(dbContext)
{
}
public async Task<User> GetByName(string username)
{
//code...
}
}
builder.RegisterType<OAuthProvider>().As<DbContext> ().InstancePerLifetimeScope() //I give DbContext as singleton here.
`
You can use a feature provided by Autofac that will wrap the OAuthAuthroizationServerMiddleware. That way the OAuth middleware and all its dependencies will be instantiated by Autofac for each request, so no singletons are involved.
Please have a read through the relevant documentation and a sample I put together in this GitHub repository.
Related
I am learning to code in c# and I am developing an API application. My GET method works but I have issues with my DELETE, it returns a success code(200) but it does not delete from my database which is connected to my application. I am using the unit of work and repository patterns and my code is as follows:
Controller code:
private readonly IOrderService _orderService;
public OrdersController(IOrderService orderService)
{
_orderService = orderService;
}
[HttpDelete("{id}")]
public async Task<ActionResult> RemoveOrder(int id)
{
try
{
await _orderService.Delete(id);
return StatusCode(200);
}
catch (Exception ex)
{
return StatusCode(500);
}
}
Service Interface
public interface IOrderService
{
Task<Order> Get(int id);
Task Add(Order order);
Task Delete(int id);
Task Update(int id, Order order);
Task<IEnumerable<Order>> GetAllOrdersAsync();
Task<IEnumerable<OrderDTO>> GetOrdersToCityAsync(string cityName);
Task<OrderDTO> GetEmployeeOrdersToCountryAsync
(
string countryName, string employeeLastName
);
}
Service class:
public class OrderService : IOrderService
{
private readonly IUnitOfWork _unitOfWork;
public OrderService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public async Task Delete(int id)
{
try
{
var order = await _unitOfWork.OrderRepository.Get(id);
_unitOfWork.OrderRepository.Delete(order);
await _unitOfWork.CommitAsync();
}
catch (Exception e)
{
await _unitOfWork.RollbackAsync();
throw;
}
}
}
Unit of work class:
public class UnitOfWork : IUnitOfWork
{
private readonly NorthwindContext _db;
private List<object> _customRepositories = new List<object>();
private IProductRepository _productRepository;
private IOrderRepository _orderRepository;
public UnitOfWork(
NorthwindContext db,
IProductRepository ProductRepository,
IOrderRepository orderRepository
)
{
_db = db;
_productRepository = ProductRepository;
_orderRepository = orderRepository;
}
uow interface:
public interface IUnitOfWork
{
IProductRepository ProductRepository { get; }
IOrderRepository OrderRepository { get; }
Task CommitAsync();
Task RollbackAsync();
}
Order repository interface which extends my genericRepository:
public interface IOrderRepository : IGenericRepository<Order>
{
Task<IEnumerable<OrderDTO>> GetOrdersToCityAsync(string cityName);
Task<OrderDTO> GetEmployeeOrdersToCountryAsync
(
string countryName, string employeeLastName
);
}
Order repository:
public class OrderRepository : GenericRepository<Order>, IOrderRepository
{
private readonly NorthwindContext _northwindContext;
public OrderRepository(NorthwindContext db) : base(db)
{
_northwindContext = db;
}
generic repository:
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
protected readonly NorthwindContext _db;
public GenericRepository(NorthwindContext db)
{
_db = db;
}
public void Delete(T entity)
{
_db.Set<T>().Remove(entity);
}
Please ignore if the curly braces are not closed properly, in my application they are.
Please check the following items:
Unit of work implementation calls SaveChanges() on CommitAsync implementation.
NorthwindContext object instance passed to repositories is the same instance as the one injected into UnitOfWork class. Otherwise you'll be working in different transactions.
You could delete an entry from database while using the following code.
[HttpDelete{"id"}]
Public async<Task<ActionResult>> DeleteItem (int id)
{ try{
Var itemToDelete = await UnitofWork.OrderRepository.GetAsync(id);
If (Id!= null) {
await Orderservice.Delete(itemToDelete);
var result = await UnitofWork.SaveChangesAsync();
If (result) return StatusCode(200);
Else return BadRequest();
return ok(itemToDelete);
} catch(exception ex) {
Throw new Error("Problem while deleting!");
}
Return BadRequest();
}
}
Just check if the item you would want ro delete is null or not. Then attempt to delete it from database. Hoping it would give you an idea.
Hi following is my custom module for Autofac DI.
public class AutofacBusinessModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<BaseService>().As<IComponentContext>().InstancePerRequest();
builder.RegisterGeneric(typeof(GenericRepository<>)).As(typeof(IGenericRepository<>));
builder.RegisterType<TrainingModuleContext>().As<IDataContext>().InstancePerLifetimeScope();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();
builder.RegisterType<RegionRepository>().As<IRegionRepository>().InstancePerLifetimeScope();
builder.RegisterType<CourseRepository>().As<ICourseRepository>().InstancePerLifetimeScope();
builder.RegisterType<TrainingRepository>().As<ITrainingRepository>().InstancePerLifetimeScope();
builder.RegisterType<TrainingService>().As<ITrainingService>().InstancePerLifetimeScope();
base.Load(builder);
}
}
This is my base service class
public abstract class BaseService
{
protected IComponentContext IComponentContext;
protected BaseService(IComponentContext componentContext)
{
this.ComponentContext = componentContext;
}
}
This is my training Service calss.
public class TrainingService : BaseService, ITrainingService { private IUnitOfWork _unitOfWork => ComponentContext.Resolve<IUnitOfWork>();
// private readonly IUnitOfWork _unitOfWork;
public TrainingService(IComponentContext componentContext) : base(componentContext)
{
//_unitOfWork = unitOfWork;
//this.componentContext = componentContext;
}
public async Task<IReadOnlyList<Training.Domain.Entities.Training>> GetAll()
{
var data = await _unitOfWork.GetRepository<Training.Domain.Entities.Training>().GetAllAsync();
return data;
}
public async Task AddTraining(Training.Domain.Entities.Training training)
{
await _unitOfWork.GetRepository<Training.Domain.Entities.Training>().AddAsync(training);
_ = await _unitOfWork.SaveAsync();
}
}
But on build I am getting always error like
System.ArgumentException: 'The type 'TrainingAPI.Services.BaseService' is not assignable to service 'Autofac.IComponentContext'.'
Please help me what mistake I am doing.
I don't no which pattern this is, but I want to accomplish to add an IEnumerable of multiple classes which uses DI also. In my example I want to inject the IEnumerable<ICustomRepository> in the BaseRepository, filled with the Custom2Repository and Custom2Repository classes which have this ICustomRepository interface and uses also injection.
Can anybody help me in the right direction?
This is the main class
public class BaseRepository : IBaseRepository
{
private readonly IProvider _provider;
private readonly DbContext _dbContext;
private readonly IEnumerable<ICustomRepository> _customRepositories;
private string _databaseName;
public BaseRepository(IProvider provider, DbContext dbContext, **IEnumerable<ICustomRepository> customRepositories**)
{
_provider = provider;
_dbContext = dbContext;
_customRepositories = customRepositories;
}
public async Task ChangeAsync(string id, CancellationToken cancellationToken)
{
var tracker = _provider.Get();
var change = tracker.GetChange(id);
foreach (var repo in **_customRepositories**)
if (repo.EntityName == change.EntityName)
{
_databaseName = repo.DatabaseName;
repo.Method1(id, cancellationToken)
}
await tracker.SaveChangesAsync(_databaseName, cancellationToken);
}
...
}
This I want to inject the base IEnumerable in the baseRepository
public class Custom1Repository : ICustomRepository
{
public Custom1Repository(IProvider provider, DbContext dbContext)
{
_provider = provider;
_tracker = tracker.Get();
_dbContext = dbContext;
}
public string EntityName => "EntityOne";
public string DatabaseName { get; private set; }
public async Task Method1Async(string id, CancellationToken cancellationToken)
...
}
This I want to inject the base IEnumerable in the baseRepository too
public class Custom2Repository : ICustomRepository
{
public Custom2Repository(IProvider provider, DbContext dbContext)
{
_provider = provider;
_tracker = tracker.Get();
_dbContext = dbContext;
}
public string EntityName => "EntityTwo";
public string DatabaseName { get; private set; }
public async Task Method1Async(string id, CancellationToken cancellationToken)
...
}
Thanks for the input. I solved it by removing the ITracker in the Custom1Repository and Custom2Repository classes. I already had this 2 classes registered in the serviceCollection as mentioned below.
You can do it like so:
serviceCollection
.AddSingleton<ICustomRepository , Custom1Repository>();
serviceCollection
.AddSingleton<ICustomRepository , Custom2Repository>();
Then use it like:
public BaseRepository(IProvider provider, DbContext dbContext, IEnumerable<ICustomRepository> customRepositories)
{
_provider = provider;
_dbContext = dbContext;
_customRepositories = customRepositories;
}
you can't do this.
Try inject a CustomRepositoryFactory instead. And with this class you could create ICustomRepository.
this is my code in .net core 3.1 to implement repository unitofwork and generic.
I write repository,user repository, unitofwork, contex and so.
after run the app there is an error :
InvalidOperationException: Unable to resolve service for type 'Repository.UnitOfWork'
I dont know what should I pass to the context or unitofwork as 'DbContextOptions'
this is my controller:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
UnitOfWork db;
public HomeController(ILogger<HomeController> logger, UnitOfWork db)
{
_logger = logger;
this.db = db;
}
}
this is my context:
public PandanetContext(DbContextOptions<PandanetContext> options) : base(options)
{
}
this is my unit of work:
public class UnitOfWork : IDisposable
{
PandanetContext db;
public UnitOfWork(PandanetContext db)
{
this.db = db;
}
private UserRepository userRepository;
public UserRepository UserRepository
{
get
{
if (userRepository == null)
{
userRepository = new UserRepository(db);
}
return userRepository;
}
}
}
this is my Repository:
public class UserRepository : Repository<UserDomainModel>
{
PandanetContext db;
public UserRepository(PandanetContext context) : base(context)
{
db = context;
}
}
this is actionResult :
public IActionResult Index()
{
UserDomainModel user = new UserDomainModel();
user.Name = "تست";
db.UserRepository.create(user);
db.UserRepository.Save();
return View();
}
in startup.cs:
services.AddDbContext<PandanetContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
You need to register the UnitOfWork:
In your startup.cs you can add the UnitOfWork to the services provider:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<UnitOfWork>();
//... etc.
}
I am still learning UnitOfWork pattern and I am not comfortable with this yet. I found many examples but nothing is clear enough for my problem.
I want use UnitOfWork with Ado.Net.
I have many repositories. I want call different methods from different repositories in same transaction using Unit of work.
For example a have this 2 repositories.
public class FirstRepository : IFirstRepository
{
private readonly ILogger logger;
private readonly IImportConfiguration configuration;
public FirstRepository(ILogger logger, IImportConfiguration configuration)
{
this.logger = logger;
this.configuration = configuration;
}
public int Save()
{
//Save to DB with Ado.Net
return 1;
}
}
public class SecondRepository : ISecondRepository
{
private readonly ILogger logger;
private readonly IImportConfiguration configuration;
public SecondRepository(ILogger logger, IImportConfiguration configuration)
{
this.logger = logger;
this.configuration = configuration;
}
public int Update()
{
//Update in DB with Ado.Net
return 1;
}
}
I want call functions Save() and Update() in same transaction.
using (var uow = UnitOfWorkFactory.Create())
{
firstRepository.Save();
secondRepository.Update();
_unitOfWork.SaveChanges();
}
Problem is how to use same UnitOfWork in both repositories ? Only thing I can see is add additional parameter to functions
//in first repository
Save(IUnitOfWork uow)
//in second repository
Update(IUnitOfWork uow)
//****************************
using (var uow = UnitOfWorkFactory.Create())
{
firstRepository.Save(uow);
secondRepository.Update(uow);
_unitOfWork.SaveChanges();
}
This is ugly solution, because i must have this parameter in all functions that work with DB.
I am using Dependency injection. ILogger and IImportConfiguration are injected with AutoFac. Maybe would be good to register all repositories in UnitOfWork? But how to do that? I cant have just one instance injected in all repositories.
Any idea?
public class UnitOfWork
{
public DbSet<Company> Companies { get; set; }
public int SaveChanges()
{
underlyingContext.SaveChanges();
}
}
public class UnitOfWorkFactory
{
public UnitOfWork Create()
{
// real creation logic
return new UnitOfWork();
}
}
public class CompanyRepository
{
private readonly UnitOfWork uow;
public CompanyRepository(UnitOfWork uow)
{
uow = uow;
}
public void Add(Company company)
{
uow.Companies.Add(company);
}
}
public class CompanyRepositoryFactory
{
public Create(UnitOfWork uow)
{
new CompanyRepository(uow);
}
}
Tying it all together:
var uow = new UnitOfWorkFactory().Create();
var companyRepository = new CompanyRepositoryFactory().Create(uow);
So to use DI, you need to create interfaces for all these.
The unit of work is based round some Data Layer connection, for example EF uses DbContext which you would use in the underlying UnitOfWork class.
Other things you can do is make IUnitOfWork (the interface) inherit IDisposable so you use the using().
To make it so you don't have a hundred repository classes (although not really a bad thing) you can make it Generic, so IRepository<T> and Repository<T>
So for a generic repo and unit of work using EF.
public class UnitOfWork : IUnitOfWork
{
ProjectDbContext context;
public UnitOfWork() {
context = new ProjectDbContext();
}
public IQueryable<T> Query<T>(Expression<Func<bool, t>> predicate)
{
return context.Set<T>().Where(predicate);
}
public void Add<T>(T entity)
{
context.Set<T>().Add(entity);
}
public int SaveChanges()
{
return context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
public class UnitOfWorkFactory
{
Lazy<UnitOfWork> lazyUOW = new Lazy<UnitOfWork>(() => new UnitOfWork());
public UnitOfWork Create()
{
// having the DI initialise as Singleton isn't enough.
return lazyUOW.Value;
}
}
public class Repository<T> : IRepository<T>
{
private readonly IUnitOfWork uow;
public Repository(IUnitOfWork uow)
{
uow = uow;
}
public void Add(T entity)
{
uow.Add(entity);
}
public List<T> AllBySomePredicate(Expression<Func<bool, T>> predicate)
{
return uow.Query(predicate).ToList();
}
}
public class RepositoryFactory : IRepositoryFactory
{
public Create<T>(UnitOfWork uow)
{
new Repistory<T>(uow);
}
}
Usage:
public class CompanyController : Controller
{
private readonly IUnitOfWorkFactory uowFactory;
private readonly IRepositoryFactory repoFactory;
public CompanyController (
IUnitOfWorkFactory uowFactory,
IRepositoryFactory repoFactory)
{
uowFactory = uowFactory;
repoFactory = repoFactory;
}
public ActionResult Index()
{
using(var uow = uowFactory.Create())
{
var companyRepo = repoFactory.Create<Company>(uow);
return View(companyRepo.AllBySomePredicate(x => x.CompanyJoined == DateTime.Now.AddMonths(-2)));
}
}
}