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>();
Related
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'm trying to use Entity Framework Core with ASP.NET Boilerplate .NET Core, but I don't want to use Repository built-in functions.
There is a problem with my DB context; it keeps returning:
System.ArgumentNullException: 'Value cannot be null.'
for the DbContext instance as shown below:
public class MainProjectsAppService : ApplicationService
{
private readonly DecentralizationDbContext _ctx;
public MainProjectsAppService(IDbContextProvider<DecentralizationDbContext> dbContextProvider)
{
_ctx = dbContextProvider.GetDbContext();
}
public void CustomizedCreateMainProject(MainProject mainProject)
{
MainProject customizedMainProject = new MainProject
{
...
};
_ctx.MainProjects.Add(customizedMainProject);
_ctx.SaveChanges();
}
}
Below is the DbContext class code:
namespace Decentralization.EntityFrameworkCore
{
public class DecentralizationDbContext : AbpZeroDbContext<Tenant, Role, User, DecentralizationDbContext>
{
/* Define a DbSet for each entity of the application */
public DbSet<MainProject> MainProjects { get; set; }
public DecentralizationDbContext(DbContextOptions<DecentralizationDbContext> options)
: base(options)
{
}
}
}
Do not call dbContextProvider.GetDbContext() in the constructor.
Define a getter instead:
public class MainProjectsAppService : ApplicationService
{
private readonly IDbContextProvider<DecentralizationDbContext> _dbContextProvider;
private DecentralizationDbContext _ctx => _dbContextProvider.GetDbContext();
public MainProjectsAppService(IDbContextProvider<DecentralizationDbContext> dbContextProvider)
{
_dbContextProvider = dbContextProvider;
}
}
Reference: aspnetboilerplate/aspnetboilerplate#4809
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();
I am using repository pattern on EF Core and Autofac in a windows service.
I have a service that needs to connect with the some dozen databases which have the same schema (same dbcontext) but only different data.
How can I achieve this in my service using Autofac? Belo
public class ReportRepository : IReportRepository
{
private readonly ReportDbContext dbContext;
public ReportRepository(ReportDbContext dbContext)
{
this.dbContext = dbContext
}
public SomeModel GetData()
{
return dbContext.SalesData;
}
}
public class ReportService : IReportService
{
private readonly IReportRepository reportRepositoryEUServer;
public ReportService(IReportRepository reportRepositoryEUServer)
{
this.reportRepositoryEUServer = reportRepositoryEUServer
}
public SomeModelDto GenerateReport()
{
var euData = reportRepositoryEUServer.GetData();
// I need to call other servers (e.g LATAM) here and get the data and aggregate them with euData
}
}
Create base context including all settings, dbsets etc:
public abstract class BaseContext : DbContext
{
public BaseContext(DbContextOptions options)
: base(options)
{ }
public DbSet<object> FirstSet { get; set; }
...
}
inherit from BaseContext for both DBs
public class LATAMContext : BaseContext
{
public LATAMContext(DbContextOptions<LATAMContext> options) : base(options)
{
}
}
public class EUContext : BaseContext
{
public EUContext(DbContextOptions<EUContext> options) : base(options)
{
}
}
and register both in Startup.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDbContext<LATAMContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LATAMConnectionString")));
services.AddDbContext<EUContext>(options => options.UseSqlServer(Configuration.GetConnectionString("EUConnectionString")));
// Autofac
var builder = new ContainerBuilder();
// needed only if you plan to inject ICollection<BaseContext>
builder.RegisterType<LATAMContext>().As<BaseContext>();
builder.RegisterType<EUContext>().As<BaseContext>();
builder.Populate(services);
return new AutofacServiceProvider(builder.Build());
}
add connection strings in appsettings.json
"ConnectionStrings": {
"LATAMConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true",
"EUConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
}
and now you can inject both contexts
public class ReportRepository : IReportRepository
{
private readonly LATAMContext latamDbContext;
private readonly EUContext euDbContext;
public ReportRepository(LATAMContext latamDbContext, EUContext euDbContext)
{
this.latamDbContext = latamDbContext;
this.euDbContext = euDbContext;
}
}
or if you plan to inject collection of contexts
public class ReportRepository : IReportRepository
{
private readonly ICollection<BaseContext> dbContexts;
public ReportRepository(ICollection<BaseContext> dbContexts)
{
this.dbContexts = dbContexts;
}
}
to access specific context
var _euContext = dbContexts.FirstOrDefault(x => x is EUContext) as EUContext;
var _latamContext = dbContexts.FirstOrDefault(x => x is LATAMContext) as LATAMContext;
I have a WindowsForm Project With this design :
DAL(GenericRepository => UnitOfWork) => BLL(Service) => UI
And use EntityFramWork, Interface, GenericRepository, Dependency Injection
My Code in Repository(DAL) :
public class Repository : RepositoryBase, IDisposable, IRepository where T : class
{
private readonly DbSet dbSet;
private bool disposed = false;
public Repository(GlobalERPEntities dbContext)
{
DBContext = dbContext;
dbSet = DBContext.Set();
}
public virtual IEnumerable GetAll()
{
return dbSet.ToList();
}
}
UnitOfWork(DAL) :
public class UnitOfWork : RepositoryBase, IUnitOfWork, IDisposable
{
private Dictionaryobject> repositories;
private bool disposed = false;
public UnitOfWork(GlobalERPEntities dbContext)
{
DBContext = dbContext;
}
public IRepository Repository() where T : class
{
if (repositories == null)
{
repositories = new Dictionaryobject>();
}
if (repositories.Keys.Contains(typeof(T)) == true)
{
return repositories[typeof(T)] as Repository;
}
Repository repo = new Repository(DBContext);
repositories.Add(typeof(T), repo);
return repo;
}
Service(BLL) :
public class Service_HR_Person : IService_HR_Person , IDisposable
{
private readonly IUnitOfWork UnitOfWork;
public Service_HR_Person(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
public virtual IEnumerable GetAll()
{
return UnitOfWork.Repository().GetAll().ToList();
}
MyForm(UI) :
using (Service_HR_Person srvPerson = new Service_HR_Person())
{
srvPerson.Delete(base.rowid);
try
{
srvPerson.Save();
MessageManager.Show(Enums.MessageBoxType.InformationTransactionSuccessfully);
}
catch (Exception ex)
{
MessageManager.Show(ErrorManager.ProccessException(ex), Enums.MessageBoxType.Error);
}
}
Iknow should not use DAL Layer in UI layer and BLL is between DAL and UI
but i have error in ui
using (Service_HR_Person srvPerson = new Service_HR_Person())
"new Service_HR_Person()" say need an arguman in () that is unitofwork but we should not use unitofwork in UI
i read some article and sample that use IOC , ninject ,bootstraper and ... but i cant write true code
How To use Ninject or IOC?
please help me with code
thankyou
add a new project to solution with name "Configure"
add castle.windsor from NuGet to all project
add a class to this project with name "Bootstrapper" and write this code
public static WindsorContainer Container = null;
public static void WireUp()
{
Container = new WindsorContainer();
Container.Register(Component.For<GlobalERPEntities>());
Container.Register(Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>());
Container.Register(Component.For<IService_HR_Person>().ImplementedBy<Service_HR_Person>());
}
and edit your code in UI
using (Service_HR_Person srvPerson = Bootstrapper.Container.Resolve<Service_HR_Person>())
{
srvPerson.Delete(base.rowid);
try
{
srvPerson.Save();
RemoveRow();
MessageManager.Show(Enums.MessageBoxType.InformationTransactionSuccessfully);
}
catch (Exception ex)
{
MessageManager.Show(ErrorManager.ProccessException(ex), Enums.MessageBoxType.Error);
}
}
this line
using (Service_HR_Person srvPerson = Bootstrapper.Container.Resolve<Service_HR_Person>())
and edit Program.cs with this code
static void Main(string[] argss)
{
Bootstrapper.WireUp();
this is work corectly