I have a ServiceModule class which extends Module:
public class ServiceModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
var ConnA = ConfigurationManager.ConnectionStrings["ConnA"].ConnectionString;
var ConnB = ConfigurationManager.ConnectionStrings["ConnB"].ConnectionString;
builder.Register(c => new SqlConnection(ConnA)).As<IDbConnection>().InstancePerLifetimeScope();
builder.RegisterType<ServiceA>().As<IServiceA>();
builder.RegisterType<ServiceB>().As<IServiceB>();
}
}
My ServiceA:
public class ServiceA: GenericRepo<Model>, IServiceA
{
public ServiceA(IDbConnection conn) : base(conn) { this.conn = conn; }
public async Task<RModel<Model>> Method(Model model)
{
return await ResultGet("ProcedureName", new
{
parameters...
}, parameters...);
}
}
Connection is passed to GenericRepo which has the ResultGet method. This method connects to database via connection and get data.
My GenericRepo:
public class GenericRepo<T> : IGenericRepo<T> where T : BaseModel
{
protected IDbConnection conn;
public GenericRepo(IDbConnection conn)
{
this.conn = conn;
}
public async Task<Model<T>> ResultGet(parameters)
{
var result = await conn.QueryAsync<T>(parameters);
}
}
So, my question is; how can I register ServiceA with ConnA and ServiceB with ConnB?
Thanks for your help.
Related
Using SqlSugar ORM, based on blazor, dependency injection business service, an error is reported when calling, and it is empty。
SqlSugarService:
public static class SqlSugarService
{
private static readonly ILog log = LogManager.GetLogger(typeof(SqlSugarService));
public static void AddSqlSugarSevice(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));
services.AddScoped<ISqlSugarClient>(o =>
{
var listConfig = new List<ConnectionConfig>();
listConfig.Add(new ConnectionConfig
{
DbType = DbType.SqlServer,
ConnectionString = "Server=.\\SQLEXPRESS;DataBase=Test;Uid=sa;Pwd=123456",
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute
});
var dbContext = new SqlSugarClient(listConfig);
return dbContext;
});
}
}
The interface:
public interface IReportRepository
{
public DataTable GetTest(string sql);
}
Interface implementation:
public class ReportRepository : IReportRepository
{
private ISqlSugarClient _dbBase;
public ReportRepository(ISqlSugarClient sqlSugar)
{
_dbBase = sqlSugar;
}
public DataTable GetTest(string sql)
{
return _dbBase.Ado.GetDataTable(sql);
}
}
Injection:
services.AddSqlSugarSevice();
services.TryAddTransient<IReportRepository, ReportRepository>();
Used in component code:
public partial class Report
{
[Inject]
public IReportRepository ReportService { get; set; }
public Report()
{
ReportService.GetTest("select * from test");
}
}
ERROR :
System.NullReferenceException,HResult=0x80004003,Message=Object reference not set to an instance of an object, Source=MyReport
I am new to IoC, especially with Autofac. Some days I was confused with IoC in the Windows Application Form. The obstacle is how to display (like: Show, ShowDialog) the form that has been registered. While IContainer can only be accessed locally (private) Program.cs.
Actually, can IoC be used in the Windows Application Form? I gave a sample code that confused me.
#
# Demo.Core Project
#
namespace Demo.Core.Repository
{
public interface IBaseRepository<T>
{
DbConnection CreateConnection();
IEnumerable<T> Get(IDbTransaction transaction = null, int? commandTimeout = null);
}
public abstract class BaseRepository<T> : IBaseRepository<T> where T : class
{
public DbConnection CreateConnection()
{
return new SqlConnection("Data Source=localhost;User ID=sa;Password=Default!3;Initial Catalog=DemoIoC;");
}
public IEnumerable<T> Get(IDbTransaction transaction = null, int? commandTimeout = null)
{
using (var connection = CreateConnection())
return connection.GetAll<T>(transaction, commandTimeout);
}
}
public interface IUserRepository : IBaseRepository<User> { }
public class UserRepository : BaseRepository<User>, IUserRepository { }
}
namespace Demo.Core.Models
{
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
}
#
# Demo.Winform Project
#
using Demo.Core.Models;
using Demo.Core.Repository;
namespace Demo.Winform
{
static class Program
{
public static IContainer Container;
[STAThread]
static void Main()
{
Container = Configure();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
static IContainer Configure()
{
var builder = new ContainerBuilder();
builder.RegisterType<UserRepository>().As<IUserRepository>();
builder.RegisterType<UserManagerForm>();
return builder.Build();
}
}
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
button1.Click += new EventHandler(delegate (object sender, EventArgs e)
{
using (var container = *** HOW TO GET CONTAINER ? ***)
{
Form manager = container.Resolve<UserManagerForm>();
manager.ShowDialog();
}
});
}
}
public partial class UserManagerForm : Form
{
private readonly IUserRepository repository;
public UserForm(IUserRepository repository) : this()
{
this.repository = repository;
}
public UserForm()
{
InitializeComponent();
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
listBox1.ValueMember = "Id";
listBox1.DisplayMember = "Name";
listBox1.DataSource = repository.Get();
}
}
}
I have read how to register form types in containers: Autofac - Register all Windows Forms. But the question is, how do I resolve the form that was registered and show form?
Thank you.
This worked for me ,You just get the service from the container \
static class Program
{
public static IContainer Container;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Container = Configure();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(Container.Resolve<IWindowsFormsApp3Client>()));
}
static Autofac.IContainer Configure()
{
var builder = new ContainerBuilder();
builder.Register<IWindowsFormsApp3Client>(ctor => new WindowsFormsApp3Client(new Uri("https://localhost:44381"), new CustomLoginCredentials()))
.AsImplementedInterfaces();
// builder.RegisterType<WindowsFormsApp3Client>().As<IWindowsFormsApp3Client>();
builder.RegisterType<Form1>();
return builder.Build();
}
}
public class CustomLoginCredentials : ServiceClientCredentials
{
private string AuthenticationToken { get; set; }
public override async Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// AuthenticationToken = Extensions.GetAppsettingsToken()?.AccessToken;
if (AuthenticationToken != null)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AuthenticationToken);
}
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
await base.ProcessHttpRequestAsync(request, cancellationToken);
}
}
We are developing windows service, and i want to change dbcontext class dynamically in repositories.
bellow is the scenario.
I have three db context classes
public abstract class Context : DbContext, IUnitOfWork
{
protected Context(string connectionString) : base(connectionString)
{
}
}
public class PlatformContext : Context
{
private readonly string _connectionString;
public PlatformContext(string connectionString)
: base(connectionString)
{
_connectionString = connectionString;
}
}
public class PlatformReplicaContext : Context
{
private readonly string _connectionString;
public PlatformReplicaContext(string connectionString)
: base(connectionString)
{
_connectionString = connectionString;
}
}
public class TempContext : Context
{
private readonly string _connectionString;
public TempContext(string connectionString)
: base(connectionString)
{
_connectionString = connectionString;
}
}
and i have repository
public interface ICategoryRepository : IRepository<Category>
{
}
public class CategoryRepository :Repository<Category>, ICategoryRepository
{
public CategoryRepository(Context context) : base(context)
{
}
}
hence im using CQRS i have another three classes
public class CategoryBasicQuery:IRequest<BaseQueryResponse>
{
public int CategoryId { get; set; }
}
public class CategoryBasicQueryHandler : IRequestHandler<CategoryBasicQuery, BaseQueryResponse>
{
private readonly ICategoryRepository _categoryRepository;
private readonly IMapper _mapper;
public CategoryBasicQueryHandler(ICategoryRepository categoryRepository, IMapper mapper)
{
_categoryRepository = categoryRepository;
_mapper = mapper;
}
public async Task<BaseQueryResponse> Handle(CategoryBasicQuery request, CancellationToken cancellationToken)
{
var entry = await _categoryRepository.FindAsync(request.CategoryId);
if (entry == null)
{
return new NotFoundResponse();
}
var response = _mapper.Map<CategoryBasicResponse>(entry);
return response;
}
}
Now here is the issue
Here category repository should be able to execute queries in all 3 types of contexts.
but how should i register classes in using autofac?
then i came up with a solution generating repositories in run time as below
public class RepositoryFactory
{
public static TRepository GetRepositoryInstance<T, TRepository>(
params object[] args)
where TRepository : IRepository<T>
{
return (TRepository)Activator.CreateInstance(typeof(TRepository), args);
}
}
im calling this method inside CategoryBasicQueryHandler class like this
var categoryRepo = RepositoryFactory.GetRepositoryInstance<Category, CategoryRepository>(new PlatformReplicaContext("connectionString"));
but when calling from CQRS
var categoty = new Category();
var command = new CategoryBasicQuery {CategoryId = categoryId};
var result = _mediator.Send(command);
VS give me following error
and my autofac registration as follows
builder.RegisterType<CategoryService>().AsSelf();
builder.RegisterType<ActionRepository>().As<IActionRepository>();
builder.RegisterType<CategoryRepository>().As<ICategoryRepository>();
builder.RegisterType<Mapper>().As<IMapper>();
can anyone help me resolve this or suggest good method to handle this situation.
thanks.
This may give you a good starting point for a possible solution: http://autofaccn.readthedocs.io/en/latest/resolve/relationships.html#keyed-service-lookup-iindex-x-b
builder.RegisterType<PlatformContext>().Keyed<Context>("platform");
builder.RegisterType<PlatformReplicaContext>().Keyed<Context>("replica");
builder.RegisterType<TempContext>().Keyed<Context>("temp");
You mentioned in a comment that there is a variable named action somewhere that will indicate which implementation to use:
public class Class1
{
private readonly IIndex<string, Context> contexts;
public Class1(IIndex<string, Context> contexts)
{
this.contexts = contexts;
}
public void Whatever()
{
string action = ...; // platform, replica or temp
Context context = this.contexts[action];
...
}
}
Of course this needs to be adapted so that it will fit in the rest of your application design. A possible example could be:
Context context = this.contexts[action];
using(ILifetimeScope scope = container.BeginLifetimeScope(builder =>
{
builder.RegisterInstance(context).As<Context>();
}))
{
// Because we are resolving IMediator from the scope, the selected Context will be used in all dependencies
var mediator = scope.Resolve<IMediator>();
mediator.Send(...);
}
I have the next problem, i dont understand why this code dont work i think is because i dont injectate the class of constructor by autofac but i dont know how do that, can us help me to do that the better way?
Before I add the generator this work if i comment the generator code in service work.
This is my code:
I have a class Controller that invoke a serv:
public class ZonesController : Controller
{
private IZoneService zoneService;
public ZonesController(IZoneService zoneService)
{
this.zoneService = zoneService;
}
[HttpGet]
//Do work
}
This is the service and interface:
public class ZoneService : IZoneService
{
private readonly IZoneRepository zoneRepository;
private readonly IDtoFactory dtoFactory;
private readonly ZoneGenerator zoneGenerator;
public ZoneService(IZoneRepository zoneRepository,
IDtoFactory dtoFactory,
ZoneGenerator zoneGenerator)
{
this.zoneRepository = zoneRepository;
this.dtoFactory = dtoFactory;
this.zoneGenerator = zoneGenerator;
}
public void Add(ZoneDetailDTO zone)
{
zoneGenerator.Generate(zone);
}
//Do Work
}
public interface IZoneService
{
void Add(ZoneDetailDTO zone);
//Do Methods
}
The generator invoke ohter class, factories:
public class ZoneGenerator
{
private readonly ZoneFactory zoneFactory;
private readonly IZoneRepository zoneRepository;
public ZoneGenerator(ZoneFactory zoneFactory, IZoneRepository zoneRepository)
{
this.zoneFactory = zoneFactory;
this.zoneRepository = zoneRepository;
}
public void Generate(ZoneDetailDTO zoneModel)
{
var zone = zoneFactory.Create(zoneModel);
zoneRepository.Add(zone);
}
}
The Factory:
public class ZoneFactory
{
private readonly ZoneMapFactory zoneMapFactory;
private readonly ZoneScheduleFactory zoneScheduleFactory;
public ZoneFactory(ZoneMapFactory zoneMapFactory,
ZoneScheduleFactory zoneScheduleFactory)
{
this.zoneMapFactory = zoneMapFactory;
this.zoneScheduleFactory = zoneScheduleFactory;
}
public Zone Create(zoneDetailDTO zone)
{
var map = zoneMapFactory.Create(zone.Map.Address, zone.Map.Latitude, zone.Map.Longitude);
var schedule = zoneScheduleFactory.Create(zone.Schedule.StartHour, zone.Schedule.EndHour);
return new Zone(zone.Name,
zone.ProvinceId,
map,
schedule,
zone.Tags);
}
}
And finally my container:
//method in Startup class Asp.Net Core
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_ => Configuration);
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterModule<DefaultModule>();
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
public class DefaultModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ZoneService>().As<IZoneService>();
builder.RegisterType<ZoneRepository>().As<IZoneRepository>();
builder.RegisterType<ProvinceService>().As<IProvinceService>();
builder.RegisterType<ProvinceRepository>().As<IProvinceRepository>();
builder.RegisterType<DtoFactory>().As<IDtoFactory>();
}
}
You have missed to add to your Load method the following:
builder.RegisterType<ZoneGenerator>().AsSelf();
builder.RegisterType<ZoneFactory>().AsSelf();
builder.RegisterType<ZoneMapFactory>().AsSelf();
builder.RegisterType<ZoneScheduleFactory>().AsSelf();
public class FooController : ApiController
{
private IDb db;
public FooController (IDb context)
{
db = context;
}
public void DoSomething(string value)
{
var output = new DoSomethingElse(value);
}
}
DoSomethingElse object is used by couple of methods in this class but it's not a requirement for all the methods. How do I register and resolve DoSomethingElse?
The problem as I understand it:
public class FooController : ApiController
{
private IDb db;
public FooController (IDb context)
{
db = context;
}
public void DoSomething(string value)
{
var output = new DoSomethingElse(value);
}
}
You don't want to instantiate the DoSomethingElse type everytime you instantiate the FooController. You also want to provide it with a value at run time.
So this calls for the Factory Pattern:
public interface IDoSomethingElseFactory
{
IDoSomethingElse Create(string value);
}
public class DoSomethingElseFactory : IDoSomethingElseFactory
{
public IDoSomethingElse Create(string value)
{
// Every call to this method will create a new instance
return new DoSomethingElse(value);
}
}
public class FooController : ApiController
{
private IDb db;
private readonly IDoSomethingElseFactory doSomethingElseFactory;
public FooController (
IDb context,
IDoSomethingElseFactory doSomethingElseFactory)
{
db = context;
this.doSomethingElseFactory = doSomethingElseFactory;
}
public void DoSomething(string value)
{
// this will be the point at which a brand new
// instance of `DoSomethingElse` will be created.
var output = doSomethingElseFactory.Create(value);
}
}
Then to register this:
builder.RegisterType<DoSomethingElseFactory>()
.As<IDoSomethingElseFactory>()