Autofac Builder with Two Different Connection - c#

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

ASP.NET Core blazor dependency injection error: System.NullReferenceException?

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

Autofac Container in Windows Form Application

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);
}
}

How to dynamically change change DI using autofac?

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(...);
}

autofac instance a class in constructor

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();

AutoFac - How to register and resolve an object with parameter?

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>()

Categories