Setting env variable as string arrays in docker-compose - docker

I want to read Queue names from docker-compose.override file. For that purpose, I have made them string arrays
and defined them like this below
environment:
- RabbitMQOptions__ConnectionString=-rabbitmq
- RabbitMQOptions__BrokerName=event_demo
- RabbitMQOptions__QueueName=["sampleQueue", "daemonQueue"]
Docker compose file builds up just fine. But I am unable to get any of the values from the array.Is there any other way around to set up this env variable.
I am injecting the value from docker-compose file through Startup.cs file
services.AddSingleton<IEventBus, RabbitMQEventBus>(sp =>
{
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
var logger = sp.GetRequiredService<ILogger<RabbitMQEventBus>>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionManager>();
var options = sp.GetRequiredService<IOptionsMonitor<RabbitMQOptions>>();
return new RabbitMQEventBus(options.CurrentValue, eventBusSubcriptionsManager, rabbitMQPersistentConnection, logger, services);
});
And right here in constructor I obtain the value through dependency injection
public RabbitMQEventBus(
RabbitMQOptions options,
IEventBusSubscriptionManager subscriptionManager,
IRabbitMQPersistentConnection persistentConnection,
ILogger<RabbitMQEventBus> logger,
IServiceCollection services
)
{
_persistentConnection = persistentConnection;
_subsManager = subscriptionManager;
_options = options;
_queueName = _options.QueueName[0];
_consumerChannel = CreateConsumerChannel();
_subsManager.OnEventRemoved += SubsManager_OnEventRemoved;
_logger = logger;
_services = services;
BROKER_NAME = _options.BrokerName;
}
Here is RabbitMQOptions class
public class RabbitMQOptions
{
public string ConnectionString { get; set; }
public string BrokerName { get; set; }
public string[] QueueName { get; set; }
}

Related

Is connectionString secured from appsettings.json by using singleton pattern?

I am using Singleton pattern to access connection string from appsettings.json because I want to use it from any place. It is a secure approach to access connection string?
the following code used to access it.
connection class
public class Connection
{
public string LocalConnection { get; set; }
public string ServerConnection { get; set; }
}
Singleton Pattern
public class ConnectionHelper
{
private static ConnectionHelper _connectionHelper;
private static string _connectionStrings;
public static ConnectionHelper GetInstance()
{
if (_connectionHelper != null) return _connectionHelper;
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
_connectionStrings = config.GetConnectionString(nameof(Connection.ServerConnection));
_connectionHelper = new ConnectionHelper();
return _connectionHelper;
}
public string GetConnection()
{
return _connectionStrings;
}
}
DbContext Class
public class DbContext
{
public DbContext()
: base(GetOptions())
{
}
private static DbContextOptions GetOptions()
{
var connectionStrings = ConnectionHelper.GetInstance();
var connection = connectionStrings.GetConnection();
var optionsBuilder = new DbContextOptionsBuilder<DbContext>();
optionsBuilder.UseSqlServer(connection);
return optionsBuilder.Options;
}
}
There's nothing wrong about using singletons to store some configuration settings no matter if it's db connection string or something else.
The credentials are as secure as your appsettings.json file on the server.

Unable to resolve service for type 'System.String' while attempting to activate service 'SQLConnConfig'

I am using blazor web assembly hosted. In Project.Client, I have the following files under data folder.
myProject.Client/Data/SQLConnConfig.cs:
public class SQLConnConfig
{
public string Value { get; }
public SQLConnConfig(string value) => Value = value;
}
myProject.Client/Data/MyService.cs:
public class MyService
{
public static SQLConnConfig _conn;
public SqlConnection connection;
public MyService(SQLConnConfig conn)
{
_conn = conn;
connection = new SqlConnection(_conn.Value);
}
public List<Item> GetItem()
{
......
}
myProject.Client/Data/Item.cs:
public class Item
{
[Key]
public string Id { get; set; }
public string Name{ get; set; }
}
Registered service in MyProject.Client/program.js
builder.Services.AddScoped<MyService>();
In myProject.Server/startup.cs:
var sqlConnConfig = new SQLConnConfig(Configuration.GetConnectionString("DefaultConnection"));
services.AddSingleton<SQLConnConfig>(sp => sqlConnConfig);
services.AddServerSideBlazor(x => x.DetailedErrors = true);
services.AddSingleton<MyService>();
App setting has connection string included.
In the index.razor: I inject and use the service.
#inject MyService MyService
protected override async Task OnInitializedAsync()
{
result = MyService.GetItem();
}
I get an error saying "Unhandled exception rendering component: Unable to resolve service for type 'System.String' while attempting to activate 'MyProject.Client.Data.SQLConnConfig". May I know where I am going wrong. Thank you.
Provide your SQLConnConfig class like this:
var sqlConnConfig = new SQLConnConfig(Configuration.GetConnectionString("DefaultConnection"));
builder.Services.AddScoped<SQLConnConfig>(sp => sqlConnConfig );
No need for static in public static SQLConnConfig _conn;
The error is coming from injection trying to construct the SQLConnConfig class.

BreezeSharp Attach Property key not found

I'm implementing an application with Breezesharp. I ran into a issue when insert the entity in the EntityManager. The error is:
There are no KeyProperties yet defined on EntityType: 'TransportReceipt:#Business.DomainModels'
I already faced this error with my first entity type "Customer" and implement a mismatching approach as suggested here. In that case I made the get operation against my WebApi with success. But now I'm creating the TransportReceipt entity inside my application.
Mapping mismatch fix
public static class ExtendMap
{
private static bool? executed;
public static void Execute(MetadataStore metadataStore) {
if (ExtendMap.executed == true)
{
return;
}
var customerBuilder = new EntityTypeBuilder<Customer>(metadataStore);
customerBuilder.DataProperty(t => t.id).IsPartOfKey().IsAutoIncrementing();
var transportReceiptBuilder = new EntityTypeBuilder<TransportReceipt>(metadataStore);
transportReceiptBuilder.DataProperty(t => t.id).IsPartOfKey().IsAutoIncrementing();
var transportReceiptAttachmentBuilder = new EntityTypeBuilder<TransportReceiptAttachment>(metadataStore);
transportReceiptAttachmentBuilder.DataProperty(t => t.id).IsPartOfKey().IsAutoIncrementing();
var uploadedFileBuilder = new EntityTypeBuilder<UploadedFile>(metadataStore);
uploadedFileBuilder.DataProperty(t => t.id).IsPartOfKey().IsAutoIncrementing();
ExtendMap.executed = true;
}
}
My base dataservice core code
public abstract class SimpleBaseDataService
{
public static string Metadata { get; protected set; }
public static MetadataStore MetadataStore { get; protected set; }
public string EntityName { get; protected set; }
public string EntityResourceName { get; protected set; }
public EntityManager EntityManager { get; set; }
public string DefaultTargetMethod { get; protected set; }
static SimpleBaseDataService()
{
try
{
var metadata = GetMetadata();
metadata.Wait();
Metadata = metadata.Result;
MetadataStore = BuildMetadataStore();
}
catch (Exception ex)
{
var b = 0;
}
}
public SimpleBaseDataService(Type entityType, string resourceName, string targetMethod = null)
{
var modelType = typeof(Customer);
Configuration.Instance.ProbeAssemblies(ConstantsFactory.BusinessAssembly);
try
{
this.EntityName = entityType.FullName;
this.EntityResourceName = resourceName;
this.DefaultTargetMethod = (string.IsNullOrWhiteSpace(targetMethod) ? "GetAllMobile" : targetMethod);
var dataService = new DataService($"{ConstantsFactory.Get.BreezeHostUrl}{this.EntityResourceName}", new CustomHttpClient());
dataService.HasServerMetadata = false;
this.EntityManager = new EntityManager(dataService, SimpleBaseDataService.MetadataStore);
this.EntityManager.MetadataStore.AllowedMetadataMismatchTypes = MetadataMismatchTypes.AllAllowable;
// Attach an anonymous handler to the MetadataMismatch event
this.EntityManager.MetadataStore.MetadataMismatch += (s, e) =>
{
// Log the mismatch
var message = string.Format("{0} : Type = {1}, Property = {2}, Allow = {3}",
e.MetadataMismatchType, e.StructuralTypeName, e.PropertyName, e.Allow);
// Disallow missing navigation properties on the TodoItem entity type
if (e.MetadataMismatchType == MetadataMismatchTypes.MissingCLRNavigationProperty &&
e.StructuralTypeName.StartsWith("TodoItem"))
{
e.Allow = false;
}
};
}
catch (Exception ex)
{
var b = 0;
}
}
}
This is who I'm trying to add the new entity
//DataService snippet
public void AttachEntity(T entity)
{
this.EntityManager.AttachEntity(entity, EntityState.Added);
}
//Business
this.TransportReceipt = new TransportReceipt { id = Guid.NewGuid(), date = DateTime.Now, customerId = Customer.id/*, customer = this.Customer*/ };
this.Attachments = new List<TransportReceiptAttachment>();
this.TransportReceipt.attachments = this.Attachments;
TransportReceiptDataService.AttachEntity(this.TransportReceipt);
When I try to add add the entity to the EntityManager, I can see the custom mapping for all my entity classes.
So my question is what I'm doing wrong.
Ok. That was weird.
I changed the mapping for a new fake int property and works. I'll test the entire save flow soon and I'll share the result here.
Update
I moved on and start removing Breezesharp. The Breezesharp project is no up-to-date and doesn't have good integration with Xamarin. I'll appreciate any comment with your experience.

Integration test with IOptions<> in .NET Core

I pass IOption<T> to my CommandBus so I can get the settings from my ServiceBusSetting class. I want to do an integration test of my Bus. I do not want to resolve it just use new QueueCommandBus and need to pass IOptions to it.
var services = new ServiceCollection().AddOptions();
services.Configure<ServiceBusAppSettings>(Configuration.GetSection("ServiceBus"));
var options = services.BuildServiceProvider().GetService<IOptions<ServiceBusAppSettings>>();
////Act
var commandBus = new QueueCommandBus(options);
This works fine, but feels very complex code to get the IOptions<T> from my appsetting.json in my test project.
Any clue if this is the only way or is there a better way?
You don't need to create the ServiceCollection or IServiceProvider. The IConfiguration interface has a Bind() method, or from .NET Core 1.1 onwards, Get<T> which you can use to get the strongly-typed object directly:
var config = Configuration.GetSection("ServiceBus");
// .NET Core 1.0
var options = new ServiceBusAppSettings();
config.Bind(options);
// .NET Core 1.1
var options = config.Get<ServiceBusAppSettings>();
I like to add these as static methods to my AppSettings strongly-typed object, to make it convenient to load them from JSON in both my web app and from unit tests.
AppSettings.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
namespace My.Namespace
{
public class AppSettings
{
public class ServiceBusAppSettings
{
public string Setting1;
public int Setting2;
}
public class ApiSettings
{
public bool FormatJson { get; set; }
}
public class MySqlSettings
{
public string User { get; set; }
public string Password { get; set; }
public string Host { get; set; }
public string Database { get; set; }
public int Port { get; set; } = 3306;
public string GetConnectionString()
{
return $"Server={Host};Database={Database};Port={Port};Uid={User};Pwd={Password}";
}
}
public ServiceBusAppSettings ServiceBus { get; set; } = new ServiceBusAppSettings();
public ApiSettings Api { get; set; } = new ApiSettings();
public MySqlSettings MySql { get; set; } = new MySqlSettings();
// Static load helper methods. These could also be moved to a factory class.
public static IConfigurationRoot GetConfiguration(string dir)
{
return GetConfiguration(dir, null);
}
public static IConfigurationRoot GetConfiguration(string dir, string environmentName)
{
if (string.IsNullOrEmpty(environmentName))
environmentName = "Development";
var builder = new ConfigurationBuilder()
.SetBasePath(dir)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{environmentName}.json", true)
.AddEnvironmentVariables();
return builder.Build();
}
public static AppSettings GetSettings(string dir)
{
return GetSettings(dir, null);
}
public static AppSettings GetSettings(string dir, string environmentName)
{
var config = GetConfiguration(dir, environmentName);
return GetSettings(config);
}
public static AppSettings GetSettings(IConfiguration config)
{
return config.Get<AppSettings>();
}
}
}
ASP.NET Core Startup.cs: (Getting the strongly-typed settings object is often helpful at this stage, when configuring the other services...)
public class Startup
{
public Startup(IHostingEnvironment env)
{
Configuration = AppSettings.GetConfiguration(env.ContentRootPath, env.EnvironmentName);
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Configure the service collection.
services.AddOptions();
services.Configure<AppSettings>(Configuration);
// It can also be handy to get the AppSettings object here.
var settings = AppSettings.GetSettings(Configuration);
// Add framework services.
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
// Pretty-print JSON in Development
options.SerializerSettings.Formatting = settings.Api.FormatJson ? Formatting.Indented : Formatting.None;
});
// Store DB connection info in AppSettings too...
var conn = settings.MySql.GetConnectionString();
services.AddDbContext<MyDbContext>(opt => opt.UseMySql(conn));
}
}
In Test Class:
var testDir = AppContext.BaseDirectory;
var settings = AppSettings.GetSettings(testDir, "Test");
//Act
var commandBus = new QueueCommandBus(settings);

MVC Multiple Databases in one single domain model

I am writting an app based on Steve Sanderson's Pro Asp .Net MVC Framework, which uses a data modeling like described on Sports Store app on that book. My app works well, I use Castle project as IOC but I have two databases. The first one stores many kind of data and my clients information. The second one stores only medical data of each client. I need to create a class that returns data in clients table, located on database 1 and medical information of each client stored on database 2.
Below are my code:
My connectionstrings on web.config:
<add name="CNRConnectionString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=CNR;Persist Security Info=True;User ID=sa;Password=#####!" providerName="System.Data.SqlClient"/>
<add name="CNRpeConnectionString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=pe;Persist Security Info=True;User ID=sa;Password=#####!" providerName="System.Data.SqlClient"/>
My new class (just data, no table conection):
namespace DomainModel.Entities
{
public class ImprimePeriodoPaciente
{
public int CodConsulta { get; set; }
public DateTime DataConsulta { get; set; }
public string Evolucao { get; set; }
public int CodProfissional1 { get; set; }
public int CodPaciente1 { get; set; }
public string NomeProfissional { get; set; } //receives data from other db
public string NomePaciente { get; set; } //receives data from other db
public int CodProcedimento { get; set; }
public bool TagConsulta { get; set; }
public int? TagConsulta2 { get; set; }
public DateTime di { get; set; }
public DateTime df { get; set; }
}
}
This is my concrete and interface from domainmodel:
public class SqlConsultasRepository:IConsultasRepository
{
private Table<Consulta> consultasTabela;
private Table<TEvolucao> tEvolucaoTabela;
private Table<Paciente> pacientesTabela;
private Table<Funcionario> funcionariosTabela;
public SqlConsultasRepository(string connectionString)
{
consultasTabela = (new DataContext(connectionString)).GetTable<Consulta>();
tEvolucaoTabela = (new DataContext(connectionString)).GetTable<TEvolucao>();
pacientesTabela = (new DataContext(connectionString)).GetTable<Paciente>();
funcionariosTabela = (new DataContext(connectionString)).GetTable<Funcionario>();
}
public IQueryable<ImprimePeriodoPaciente> Prontuarios {
get
{
return
(
from c in consultasTabela
join p in pacientesTabela on c.CodPaciente1 equals p.CodigoPaciente //my doom
join f in funcionariosTabela on c.CodProfissional1 equals f.CodigoFuncionario //my doom
select new ImprimePeriodoPaciente
{
CodConsulta=c.CodConsulta,
DataConsulta=c.DataConsulta,
Evolucao=c.Evolucao,
NomeProfissional= f.NomeFuncionario, //my doom
NomePaciente=p.NomePaciente, //my doom
CodProfissional1=c.CodProfissional1,
CodPaciente1 = c.CodPaciente1
}
);
}
}
The code is marked with 'my doom' to show where the problem occurs.... I need to create a connectionString reference to the other database because this tables are not in current database specified by connectionString variable. I am getting error saying that the data are not from same datacontext (or shomething like that).
So, could you help?
Got my way through it based on this post:
http://dotnetprogrammingtipsbymuhil.blogspot.com.br/2009/12/query-contains-references-to-items.html
For those who get on same problem, follow above post steps.
Im my project I've created an interface to a concrete method that takes separated data from each database and put them on separated lists, as follows:
namespace DomainModel.Concrete
{
public class SqlImprimePeriodoPacientesRepository : IImprimePeriodoPacientesRepository
{
private static string cConexao = "Data Source=.\\SQLEXPRESS;Initial Catalog=CNR;Persist Security Info=True;User ID=sa;Password=23092000";
private static string cConexao2 = "Data Source=.\\SQLEXPRESS;Initial Catalog=PE;Persist Security Info=True;User ID=sa;Password=23092000";
private IConsultasRepository cRepository = new SqlConsultasRepository(cConexao2);
private IPacientesRepository pRepisotory = new SqlPacientesRepository(cConexao);
private IFuncionariosRepository fRepository = new SqlFuncionariosRepository(cConexao);
public IQueryable<ImprimePeriodoPaciente> ImprimePeriodoProntuarios//(int? codpac, DateTime? di, DateTime? df)
{
get
{
var consultas =
(
from c in cRepository.Consultas
select new
{
c.cdf,
c.cdi,
c.CodConsulta,
c.CodPaciente1,
c.CodProcedimento,
c.CodProfissional1,
c.DataConsulta,
c.df,
c.di,
c.Evolucao,
c.TagConsulta,
c.TagConsulta2
}
)
.ToList();
var pacientes =
(
from p in pRepisotory.Pacientes
select new
{
p.CodigoPaciente,
p.NomePaciente
}
)
.ToList();
var funcionarios =
(
from f in fRepository.Funcionarios
select new
{
f.CodigoFuncionario,
f.NomeFuncionario
}
)
.ToList();
var result =
(
from c in consultas
join p in pacientes on c.CodPaciente1 equals p.CodigoPaciente
join f in funcionarios on c.CodProfissional1 equals f.CodigoFuncionario
select new ImprimePeriodoPaciente
{
CodConsulta = c.CodConsulta,
DataConsulta = c.DataConsulta,
Evolucao = c.Evolucao,
NomeProfissional = f.NomeFuncionario,
NomePaciente = p.NomePaciente,
CodProfissional1 = c.CodProfissional1,
CodPaciente1 = c.CodPaciente1
}
).ToList();
return result.AsQueryable();
}
}
}
}
That method did the job on the DomainĀ“s Model side, so the rest resides on dealing with the results.
Hope this help someone!

Resources