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.
Related
It was working earlier before adding actionedService which is similar to rejectionService, throws following error
An unhandled exception occurred while processing the request.
DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Sx.Workflow.Server.Controllers.ReportController' can be invoked with the available services and parameters:
Cannot resolve parameter 'Sx.Workflow.Reporting.Services.IActionedService actionedService' of constructor 'Void .ctor(NLog.ILogger, AutoMapper.IMapper, Sx.Workflow.Reporting.Services.IRejectionService, Sx.Workflow.Reporting.Services.IActionedService)'.
Autofac.Core.Activators.Reflection.ReflectionActivator.GetValidConstructorBindings(ConstructorInfo[] availableConstructors, IComponentContext context, IEnumerable parameters) in ReflectionActivator.cs, line 160
Controller
namespace Sx.Workflow.Server.Controllers
{
[MenuItem("report")]
[ServiceFilter(typeof(SettingsFilter))]
[Authorize(Policy = Security.Constants.RolePolicy)]
public class ReportController : Controller
{
private readonly ILogger _logger;
private readonly IMapper _mapper;
private readonly IRejectionService _rejectionService;
private readonly IActionedService _actionedService;
public ReportController(ILogger logger, IMapper mapper, IRejectionService rejectionService, IActionedService actionedService)
{
_logger = logger;
_mapper = mapper;
_rejectionService = rejectionService;
_actionedService = actionedService;
}
[HttpGet]
public IActionResult Index()
{
_logger.Info("Report Controller");
return View();
}
[HttpPost]
[ApiExceptionFilter]
public async Task<IActionResult> Reject(RejectionReportRequestDto criteria)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_logger.Info("Generate Rejection Report");
var result = await _rejectionService.Generate(criteria.From, criteria.To);
var items = _mapper.Map<RejectionReportDto>(result);
return Ok(items);
}
[HttpPost]
[ApiExceptionFilter]
public async Task<IActionResult> Actioned(ActionedReportRequestDto criteria)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_logger.Info("Generate Actioned Report");
var result = await _actionedService.Generate(criteria.From, criteria.To);
var items = _mapper.Map<ActionedReportDto>(result);
return Ok(items);
}
}
}
Handler
namespace Sx.Workflow.Reporting.Handlers
{
public class ActionedReportHandler : IHandleEvent<ApplicationActionedEvent>
{
private readonly IActionedService _service;
public ActionedReportHandler(IActionedService service)
{
_service = service;
}
public Task Handle(ApplicationActionedEvent args)
{
var actioned = new Actioned
{
ApplicationNumber = args.ApplicationNumber,
AssigneeFrom = args.AssigneeFrom,
AssigneeTo = args.AssigneeTo,
DepartmentFrom = args.DepartmentFrom.Name,
DepartmentTo = args.DepartmentTo.Name,
Reason = args.RejectReasonName,
Comments = args.RejectReasonText,
RejectionDate = DateTime.Now
};
return _service.Save(actioned);
}
}
}
Service
namespace Sx.Workflow.Reporting.Services
{
public class ActionedService : IActionedService
{
private readonly ISaveActioned _saveActioned;
private readonly IGenerateActionedReport _actionedReport;
public ActionedService(ISaveActioned saveActioned, IGenerateActionedReport actionedReport)
{
_saveActioned = saveActioned;
_actionedReport = actionedReport;
}
public Task<ActionedReport> Generate(DateTime from, DateTime to)
{
return _actionedReport.Generate(from, to);
}
public Task Save(Actioned actioned)
{
return _saveActioned.Save(actioned);
}
}
}
Interface
namespace Sx.Workflow.Reporting.Services
{
public interface IActionedService
{
Task Save(Actioned actioned);
Task<ActionedReport> Generate(DateTime from, DateTime to);
}
}
Service Module
public class ServiceModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<RejectionService>()
.As<IRejectionService>()
.InstancePerLifetimeScope();
builder.RegisterType<ActionedService>()
.As<IActionedService>()
.InstancePerLifetimeScope();
}
}
Makes sense. While you are registering the type in DI, you have nothing for:
public ActionedService(ISaveActioned saveActioned, IGenerateActionedReport actionedReport)
So autofac assumes that there must be an empty constructor in ActionedService
So there are 2 solutions:
Remove the constructor parameters and create them without DI
Create the registrations for the two parameters of the constructor. Something like the following:
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<RejectionService>()
.As<IRejectionService>()
.InstancePerLifetimeScope();
builder.RegisterType<ActionedService>()
.As<IActionedService>()
.InstancePerLifetimeScope();
builder.RegisterType<SaveActioned>()
.As<ISaveActioned>()
.InstancePerLifetimeScope();
builder.RegisterType<GenerateActionedReport>()
.As<IGenerateActionedReport>()
.InstancePerLifetimeScope();
}
I have 2 interfaces:
public interface IPedidoService
{
UsuarioDrogueria CUsuarioDrogueria(string userId, int idDrogueria);
List<PedidoComboProducto> CPedidosCombosProductos(int idcombo, int idPedido);
}
public interface IEmailService
{
void SendEmailAttachment(string email, string subject, string archive);
void SendNotificationEmail(List<Pedido> pedidos, string email, Drogueria drog);
void SendNotificationEmailADM(Pedido pedido) ;
}
I want to use the functions from IEmailService inside IPedidoService, so I inject it in its constructor when I create the respository.
public class PedidoService : IPedidoService
{
private readonly IEmailService emailService;
public PedidoService(IEmailService e)
{
this.emailService = e;
}
}
Up until here everything works fine, but when I try to do reverse the roles (IPedidoService functions inside IEmailService):
public class EmailService : IEmailService
{
private readonly IPedidoService pedidoSettings;
public EmailService(IPedidoService p)
{
this.pedidoSettings = p;
}
}
I end up getting this exception:
System.InvalidOperationException: A circular dependency was detected for the service of type
'EnvioPedidos.Data.Abstract.IPedidoService'.
EnvioPedidos.Data.Abstract.IPedidoService(EnvioPedidos.PedidoService) ->
EnvioPedidos.Data.Abstract.IEmailService(EnvioPedidos.EmailService) ->
EnvioPedidos.Data.Abstract.IPedidoService
Can anybody help me trace the issue here?
A simple way is to use Lazy<T> class which is based on this blog:
Custom extension method:
public static class LazyResolutionMiddlewareExtensions
{
public static IServiceCollection AddLazyResolution(this IServiceCollection services)
{
return services.AddTransient(
typeof(Lazy<>),
typeof(LazilyResolved<>));
}
}
public class LazilyResolved<T> : Lazy<T>
{
public LazilyResolved(IServiceProvider serviceProvider)
: base(serviceProvider.GetRequiredService<T>)
{
}
}
Configure in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
//services.AddSingleton<IPedidoService, PedidoService>();
//services.AddSingleton<IEmailService, EmailService>();
services.AddLazyResolution();
}
Change your implements class:
public class PedidoService : IPedidoService
{
private readonly Lazy<IEmailService> emailService;
public PedidoService(Lazy<IEmailService> e)
{
this.emailService = e;
}
//...
}
public class EmailService : IEmailService
{
private readonly Lazy<IPedidoService> pedidoSettings;
public EmailService(Lazy<IPedidoService> p)
{
this.pedidoSettings = p;
}
//...
}
When you have 2 classes, they cannot reference each other by dependency injection. This is called a circular dependency, as shown by your error. You need a 3rd class that references both services and you can use the methods there.
public class PedidoService
{
public PedidoService()
{
}
}
public class EmailService
{
public EmailService()
{
}
}
public class Container
{
private readonly EmailService emailService;
private readonly PedidoService pedidoService;
public Container(EmailService emailService, PedidoService pedidoService)
{
this.emailService = emailService;
this.pedidoService = pedidoService;
}
//use the services here
}
I am Creating a web api using Repository pattern and 3 tier architecture. i also made a IOC Container (Autofac) for hadling dependencies. But i am keep getting error, in tried everything. The Error is: An error occurred when trying to create a controller of type 'StudentsController'. Make sure that the controller has a parameterless public constructor.
Here is my Code:
My Context Class:
public class StudentContext: DbContext
{
public StudentContext(): base("name=StudentDB")
{
//Database.SetInitializer<StudentContext>(null);
}
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new StudentMap());
}
public DbSet<Student> Students { get; set; }
}
My Repository Class:
public class Repository<T> : IRepository<T> where T : class
{
public readonly StudentContext context;
public IDbSet<T> entities;
public Repository(StudentContext _context)
{
this.context = _context;
entities = _context.Set<T>();
}
public IQueryable<T> Table()
{
return this.Entities;
}
public void Insert (T entity)
{
this.Entities.Add(entity);
this.Save();
}
private IDbSet<T> Entities
{
get
{
if (entities == null)
entities = context.Set<T>();
return this.entities;
}
}
public void Save()
{
context.SaveChanges();
}
}
My Services Class is as:
public class StudentService: IStudentService
{
public IRepository<Student> _StudentRepository;
public StudentService(IRepository<Student> sturepo)
{
this._StudentRepository = sturepo;
}
public IQueryable<Student> GetAllStudents()
{
return _StudentRepository.Table();
}
public void InsertStudent(Student std)
{
_StudentRepository.Insert(std);
}
}
My API Controller:
public class StudentsController : ApiController
{
public IStudentService studentservice;
public StudentsController(IStudentService stuservce)
{
this.studentservice = stuservce;
}
public IList<Student> GetStudents()
{
List<Student> student = studentservice.GetAllStudents().ToList();
return student.ToList();
}
}}
Autofac Container Class:
public class AutofacConfig
{
public static void ConfigureContainer()
{
var builder = new ContainerBuilder();
// Get your HttpConfiguration.
var config = GlobalConfiguration.Configuration;
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).Where(t => !t.IsAbstract && typeof(ApiController).IsAssignableFrom(t))
.InstancePerMatchingLifetimeScope();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OPTIONAL: Register the Autofac filter provider.
builder.RegisterWebApiFilterProvider(config);
// OPTIONAL: Register the Autofac model binder provider.
builder.RegisterWebApiModelBinderProvider();
// Set the dependency resolver to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
}
Calling Autofac in Global.Ascx:
protected void Application_Start()
{
AutofacConfig.ConfigureContainer();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
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>();
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.