NServiceBus MasterNode Configuration In Code To Resolve Dns Correctly - configuration

I ran into this error the other day trying to deploy using machine names instead of ip:
Could not translate format name to independent name: XXXX
After some research i found this description by Udi: http://tech.groups.yahoo.com/group/nservicebus/message/15232
Problem is we cant shut MSMQ AD off.
So instead I have made this work around, where i resolve machine name to ipv4 address:
public class MasterNodeConfiguration : IProvideConfiguration<MasterNodeConfig>
{
private const string _masterNodeMachineNameKey = "MasterNodeMachineName";
private string _masterNodeMachineName = string.Empty;
public MasterNodeConfiguration(IApplicationSettingsReader applicationSettingsReader)
{
var machineName = applicationSettingsReader.GetValue(_masterNodeMachineNameKey);
ResolveMachineNameToIpAddress(machineName);
}
private void ResolveMachineNameToIpAddress(string machineName)
{
if (string.IsNullOrEmpty(machineName) == false)
{
_masterNodeMachineName = Dns.GetHostAddresses(machineName)
.Single(address => address.AddressFamily == AddressFamily.InterNetwork)
.ToString();
}
}
public MasterNodeConfig GetConfiguration()
{
return new MasterNodeConfig
{
Node = _masterNodeMachineName,
};
}
}
I have tested this across machine boundaries and it works.
My question:
This configuration resides in the same assembly as our worker/dist/sender/publisher/subscriber configurations are placed. They are all written in code using: NServiceBus.Configure.With().DefineEndpointName ..., which means that all these configurations will pick up a MasterNode configuration with a Node value of NULL if they do not include the above appsettings key. Is this dangerous or will NSB simply handle the NULL node as if no MasterConfig was specified?

Related

azure mobile apps: tables get not created

I have been through the tutorial on how to create mobile apps with azure and was able to deploy my middle ware and connect to a table called "todoitem" (which was from the tutorial) and I was able to write data to it and read from it.
(https://learn.microsoft.com/en-us/azure/developer/mobile-apps/azure-mobile-apps/quickstarts/maui/?pivots=vs2022-windows)
I was also able to connect with SSMS to the db and see the table and the items there.
Now I wanted to create my own table (useritem).
I copied everything from the tutorial, and tried creating data on my server but was returned: 500 internal server error.
I tried everything, but never was my table created, nor could I write to it.
Then I thought:
I can just create a table in SSMS via console. So I wrote a create table statement, that looked identical to the table form the todo items, only that I also added "email" as a property.
This went through fine and I saw my table in the tree in SSMS.
I could also query data from it (all from SSMS).
When I now tried to write data to my table from my app
await _table.InsertItemAsync(item);
I was finally no longer given "internal server error".
And via SSMS I could see that my data was put on the server!
Yeiks,
No where in the tutorial did it mention that I had to set the tables up myself but anyway, things where working..
UNTIL...
I tried quering data FROM the table FROM my app (not via SSMS, that works fine).
SO I did what I already did in the tutorial which was:
return await _table.GetAsyncItems().ToListAsync();
Which when done with the TODO item s(from the tutorial) returned a list with all items on that table.
BUt when I do it now with my own table, the app crashes, I dont even get an error message, it just doesnt continue.
So my guess it, that somehow, I missed setting up the connection to the table write.
With my workaround of creating the table in SSMS I was able to write to it from my app, but still cannot get my data returned.
What part of the tutorial was I missing?
Here is some of the code in question that should be important:
program.cs:
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("C5"); // set the connection string name that you set up (caused issues before)
if (connectionString == null)
{
throw new ApplicationException("DefaultConnection is not set");
}
builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString));
builder.Services.AddDatasyncControllers();
var app = builder.Build();
// Initialize the database
using (var scope = app.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await context.InitializeDatabaseAsync().ConfigureAwait(false);
}
// Configure and run the web service.
app.MapControllers();
app.Run();
appDbcontext.cs:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
/// <summary>
/// The dataset for the UserItems.
/// </summary>
public DbSet<UserItem> UserItems => Set<UserItem>();
/// <summary>
/// Do any database initialization required.
/// </summary>
/// <returns>A task that completes when the database is initialized</returns>
public async Task InitializeDatabaseAsync()
{
await this.Database.EnsureCreatedAsync().ConfigureAwait(false);
}
}
my controller:
[Route("tables/useritem")]
public class tblUserController : TableController<UserItem>
{
public tblUserController(AppDbContext context)
: base(new EntityTableRepository<UserItem>(context))
{
}
}
and ofcourse the modeL.
public class UserItem : EntityTableData
{
[Required, MinLength(1)]
public string Email { get; set; } = "";
public string Telephone { get; set; } = "";
public string Password { get; set; } = "";
}
EDIT:
Also I have noticed that when I look at the link for my middleware, instead of getting a list of the items (which was the case with the todo items) I get this:

Changing database type at runtime using EntityFramework

Is it possible to change database type at runtime? If yes, how it can be done? I am using EntityFramework 6.
Background about the question:
I have an application that initially does not have database access. A user first has to go through "installation" process and provide information about the database(including database type eg. MySql or MsSql).
I would like to avoid having 2 contexts if possible. If necessary I can provide more details.
You can specify the connection string at runtime using the following...
DbContext has a constructor that can be overloaded with the name of the connection string, or the connection string itself.
public partial class EntityName: DbContext {
public EntityName(): base("name=EntityName") {}
public EntityName(string connectionString): base(connectionString) {}
}
var connString = "PopulateConnString";
Using (var ctx = new EntityName(EntityConnectionStringBuilder)
{
// Do stuff
}

appsettings.json in .netCore console application

I have an appsettings.json file with the following values
{
"MailOptions":
{
"Username": "ruskin",
"Password": "password"
}
}
When I read it via the ConfigurationBuilder I can only access the values via configuration["MailSettings:Username"]. I want to grab the entire MailOptions string, is there anyway to do that? I don't want to use Json to parse the file etc...I want to stick to configuration builder.
I would expect configuration.GetSection("MailOptions") to work? It simply returns null.
What I have tried
SomeSection aSection = new SomeSection();
ServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.Configure<SomeSection>(options => configuration.GetSection("SomeSection").Bind(aSection));
var someSection = serviceCollection.BuildServiceProvider().GetService<IOptions<SomeSection>>();
// aSection is instantiated but no values in it
// someSection is null
My appsettings.json
{
"SomeSection": {
"UserName": "ruskin",
"Password": "dantra"
}
}
And my POCO class
public class SomeSection
{
public string UserName { get; set; }
public string Password { get; set; }
}
The configuration framework is an abstraction over the underlying source types. So MailOptions:Username could come from JSON, an environment variables or even INI files - and the configuration system can even be configured with multiple sources. If need a JSON string to configure your mail library and want to use the configuration abstraction, I suggest creating a class to hold the settings and serialize it to a JSON string again.
EDIT:
Using configuration.GetSection("SomeSection").Get<SomeSection>() I can successfully get the POCO from the app. see sample application.

Castle windsor: how to pass arguments to deep dependencies?

I have the following dependency chain:
IUserAppService
IUserDomainService
IUserRepository
IUserDataContext - UserDataContextImpl(string conn)
All interfaces above and implementations are registered in a Windsor Castle container. When I use one connection string, everything works fine.
Now we want to support multiple databases, In UserAppServiceImpl.cs, we want to get different IUserRepository (different IUserDatabaseContext) according to userId as below:
// UserAppServiceImpl.cs
public UserInfo GetUserInfo(long userId)
{
var connStr = userId % 2 == 0 ? "conn1" : "conn2";
//var repo = container.Resolve<IUserRepository>(....)
}
How can I pass the argument connStr to UserDataContextImpl?
Since the connection string is runtime data in your case, it should not be injected directly into the constructor of your components, as explained here. Since however the connection string is contextual data, it would be awkward to pass it along all public methods in your object graph.
Instead, you should hide it behind an abstraction that allows you to retrieve the proper value for the current request. For instance:
public interface ISqlConnectionFactory
{
SqlConnection Open();
}
An implementation of the ISqlConnectionFactory itself could depend on a dependency that allows retrieving the current user id:
public interface IUserContext
{
int UserId { get; }
}
Such connection factory might therefore look like this:
public class SqlConnectionFactory : ISqlConnectionFactory
{
private readonly IUserContext userContext;
private readonly string con1;
private readonly string con2;
public SqlConnectionFactory(IUserContext userContext,
string con1, string con2) {
...
}
public SqlConnection Open() {
var connStr = userContext.UserId % 2 == 0 ? "conn1" : "conn2";
var con = new SqlConnection(connStr);
con.Open();
return con;
}
}
This leaves us with an IUserContext implementation. Such implementation will depend on the type of application we are building. For ASP.NET it might look like this:
public class AspNetUserContext : IUserContext
{
public string UserId => int.Parse(HttpContext.Current.Session["UserId"]);
}
You have to start from the beginning of your dependency resolver and resolve all of your derived dependencies to a "named" resolution.
Github code link:https://github.com/castleproject/Windsor/blob/master/docs/inline-dependencies.md
Example:
I have my IDataContext for MSSQL and another for MySQL.
This example is in Unity, but I am sure Windsor can do this.
container.RegisterType(Of IDataContextAsync, dbEntities)("db", New InjectionConstructor())
container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)("UnitOfWork", New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db")))
'Exceptions example
container.RegisterType(Of IRepositoryAsync(Of Exception), Repository(Of Exception))("iExceptionRepository",
New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db"),
New ResolvedParameter(Of IUnitOfWorkAsync)("UnitOfWork")))
sql container
container.RegisterType(Of IDataContextAsync, DataMart)(New HierarchicalLifetimeManager)
container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)(New HierarchicalLifetimeManager)
'brands
container.RegisterType(Of IRepositoryAsync(Of Brand), Repository(Of Brand))
controller code:
No changes required at the controller level.
results:
I can now have my MSSQL context do its work and MySQL do its work without any developer having to understand my container configuration. The developer simply consumes the correct service and everything is implemented.

Using MySQL with visual studio and changing the connection at runtime

I use something like this for my application
MySqlConnection cnn = new MySqlConnection("Server=myServerAddress;" +
"Database=myDataBase;" +
"Uid=myUsername;" +
"Pwd=myPassword;");
And this changes everytime because we deploy databases with our application.
It works fine. I type in using(new connection(cnn)){ query... } and go.
And I've got it working with a dataset using a connection defined in the windows ODBC datasouce administrator.
But I'm curious, is there a way to use visual studio's dataset items using the my local test db and then change the connection of the dataset at runtime? Even better, can I use c# to programmatically add the ODBC data source at runtime?
Usually a connection string is loaded from the application exe.config file present in the same folder of the application. This connection string could be defined using the Settings tab in the project properties.
Right click on Properties of your project
Select the Settings tab (confirm the creation if you have no
settings)
Click on the ComboBox in the column type and select Connection String
Give a symbolic name to your connection
Type the connection string in the Value column (Examples at
connectionstrings.com)
Now in your project files you should have the file app.config (that becomes yourapp.exe.config) where there is a section like this
<configuration>
<connectionStrings>
<add name="MyAppConnection"
connectionString="Server=myServerAddress;Database=myDB;Uid=user;Pwd=pass;" />
</connectionStrings>
</configuration
At this point you read it in the program using
string conString = ConfigurationManager
.ConnectionStrings["MyAppConnection"]
.ConnectionString;
Instead in a dynamic situation where you want to build yourself the connection string during runtime (from user inputs, your own configuration files and so on) then you could leverage the functionality of the class MySqlConnectionStringBuilder
MySqlConnectionStringBuilder msb = new MySqlConnectionStringBuilder();
msb.Server = "localhost";
msb.Port = 3306;
msb.UserID = "root";
msb.Password = "xxx";
msb.Database = "test";
MySqlConnection cnn = new MySqlConnection(msb.ConnectionString);
cnn.Open();
Of course, these literal values could be substituted by your own variables.
The documentation of this class is surprising difficult to find. The best docs are the one of the Sql Server equivalent. It is interesting that you could read a static connection string from your config file and then change only the property needed.
string conString = ConfigurationManager
.ConnectionStrings["MyAppConnection"]
.ConnectionString;
MySqlConnectionStringBuilder msb = new MySqlConnectionStringBuilder(conString);
msb.Database = "AnotherDB";
MySqlConnection cnn = new MySqlConnection(msb.ConnectionString);
Application connection string cannot be changed at runtime.
User settings can be changed.
Assuming you are using an application setting-property named "MyConnectionString" which holds the connection string for the entire application.
On your main Program class create a global string:
internal static string Prconnstring;
Create and save this settings.cs file:
namespace MYSOLUTIONORPROJECTNAME.Properties
{
// (Not sure where I found this solution some time ago)
// This class allows you to handle specific events on the settings class:
// The SettingChanging event is raised before a setting's value is changed.
// The PropertyChanged event is raised after a setting's value is changed.
// The SettingsLoaded event is raised after the setting values are loaded.
// The SettingsSaving event is raised before the setting values are saved.
internal sealed partial class Settings
{
public Settings()
{
// // To add event handlers for saving and changing settings, uncomment the lines below:
//
// this.SettingChanging += this.SettingChangingEventHandler;
//
// this.SettingsSaving += this.SettingsSavingEventHandler;
//
}
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e)
{
// Add code to handle the SettingChangingEvent event here.
}
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e)
{
// Add code to handle the SettingsSaving event here.
}
public override object this[string propertyName]
{
get
{
if (propertyName == "MyConnectionString")
{
return Program.Prconnstring;
}
else
{
return base[propertyName];
}
}
set
{
base[propertyName] = value;
}
}
}
}
Before calling-opening any object that uses the connection string (examples include Forms that use datasets or other classes that use datasets created on the development enviroment) create your new connection string by any means you think. (Example: You might want to use as user name in the connection string the current user. Create the connection string using the info provided form the environment.)
Program.Prconnstring = thenewruntimeconnectionstring.
Now whenever the application tries to get MyConnectionString (which is hardcoded in the myapplicationname.config and cannot be changed) instead gets the new thenewruntimeconnectionstring you provided to Program.Prconnstring.
Be aware that the development connection string will be available-visible to final user, since it is just a text file. If you do not want this, you can change that file (will be a file named NAMEOFMYAPPLICATION.exe.config) during deployment, since the connection string hardcoded there, will be of no use for the running app. Do not delete it, just change.
Your connection string will be stored in your App.config (or c# equivalent). Say it's called MyConnectionString. Just add My.Settings("MyConnectionString")="[your new connection string]" to your entry point to change to database binding at runtime. E.g:
Public Sub New()
' This call is required by the designer.
InitializeComponent()
My.Settings("MyConnectionString") = "server=remotedb.uk;user id=MainUser;password=2jdi38edhnche73g;database=mainDb;persistsecurityinfo=True;allowuservariables=True;defaultcommandtimeout=480;characterset=utf8mb4"
End Sub