Cannot query dockerized MongoDB container from dockerized ASP.NET Core 3.1 container - mongodb

I have a dockerized .net core container and am trying to query a MongoDB database. I have a REST API that is called to query the database from the .net core container. It seems as if I am able to establish a connection to the container when the instance of the service is created:
private readonly IMongoCollection<DbObject> _dbObjects;
public TaxService(IDbConfig dbConfig)
{
Console.Out.WriteLine("got here: " + dbConfig.ConnectionString);
MongoClient client = new MongoClient(dbConfig.ConnectionString);
IMongoDatabase database = client.GetDatabase(dbConfig.DatabaseName);
_dbObjects = database.GetCollection<DbObject>(dbConfig.SalesTaxCollectionName);
Console.Out.WriteLine("db initialized");
}
Here is the dbConfig object:
"DbConfig": {
"SalesTaxCollectionName": "ExampleCollection",
"ConnectionString": "mongodb://mongo:27017",
"DatabaseName": "ExampleDb"
}
It gets through this code, but when the database is actually queried, a PlatformNotSupportedException is thrown:
public DbObject GetByValue(string value)
{
Console.Out.WriteLine("querying db");
List<DbObject> matches = _dbObjects.Find(dbObject => dbObject.Value.Equals(value)).ToList();
Console.Out.WriteLine("successfully queried"); // Does not reach this point
if (matches.Any())
{
return matches.First();
}
else
{
throw new ArgumentException($"No values matched");
}
}
I have put the rest of the files in gists for convenience:
docker-compose.yml: https://gist.github.com/MinhazMurks/1fbb47afd360bbac48df45b1f0609e33
Dockerfile: https://gist.github.com/MinhazMurks/bb2b7f76d28894a81136d940b5997165
InitExampleDb.js: https://gist.github.com/MinhazMurks/9aae03daceee1e689c4e821419966f41
Full-Log: https://gist.github.com/MinhazMurks/0de9cd822fcf2930065527191127c83b
Any insight would be appreciated!

You can try to set the following line in the host file:
(It is located here in case of Windows: C:\Windows\System32\drivers\etc\hosts)
127.0.0.1 mongo
After this try connect using RoboMongo. In the Address textbox insert mongo and try to connect to it.

Related

SCDF server dual database connection error

In my spring batch task I have two datasources configured, one for oracle and another for h2.
H2 I'm using for batch and task execution tables and oracle is for real data for batch processing. I'm able to successfully run the task from ide but when I run it from SCDF server I get following error
Caused by: java.sql.SQLException: Unable to start the Universal Connection Pool: oracle.ucp.UniversalConnectionPoolException: Cannot get Connection from Datasource: org.h2.jdbc.JdbcSQLInvalidAuthorizationSpecException: Wrong user name or password [28000-200]
Question is, why is it connecting to H2 for oracle db connection as well?
Following is my DB configuration:
#Bean(name = "OracleUniversalConnectionPool")
public DataSource secondaryDataSource() {
PoolDataSource pds = null;
try {
pds = PoolDataSourceFactory.getPoolDataSource();
pds.setConnectionFactoryClassName(driverClassName);
pds.setURL(url);
pds.setUser(username);
pds.setPassword(password);
pds.setMinPoolSize(Integer.valueOf(minPoolSize));
pds.setInitialPoolSize(10);
pds.setMaxPoolSize(Integer.valueOf(maxPoolSize));
} catch (SQLException ea) {
log.error("Error connecting to the database: ", ea.getMessage());
}
return pds;
}
#Bean(name = "batchDataSource")
#Primary
public DataSource dataSource() throws SQLException {
final SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriver(new org.h2.Driver());
dataSource.setUrl("jdbc:h2:tcp://localhost:19092/mem:dataflow");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
I got it resolved, problem was I was using this for setting values to oracle db.
spring.datasource.url: ******
spring.datasource.username: ******
It worked fine from IDE, but when I ran it on SCDF server it was overwritten by default properties being used for database connection of SCDF server. So I just updated the connection properties to :
spring.datasource.oracle.url: ******
spring.datasource.oracle.username: ******
And now it's working as expected.

At what point does the MongoDB C# driver open a connection?

I'm having a problem with lots of connections being opened to the mongo db.
The readme on the Github page for the C# driver gives the following code:
using MongoDB.Bson;
using MongoDB.Driver;
var client = new MongoClient("mongodb://localhost:27017");
var server = client.GetServer();
var database = server.GetDatabase("foo");
var collection = database.GetCollection("bar");
collection.Insert(new BsonDocument("Name", "Jack"));
foreach(var document in collection.FindAll())
{
Console.WriteLine(document["Name"]);
}
At what point does the driver open the connection to the server? Is it at the GetServer() method or is it the Insert() method?
I know that we should have a static object for the client, but should we also have a static object for the server and database as well?
Late answer... but the server connection is created at this point:
var client = new MongoClient("mongodb://localhost:27017");
Everything else is just getting references for various objects.
See: http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-csharp-driver/
While using the latest MongoDB drivers for C#, the connection happens at the actual database operation. For eg. db.Collection.Find() or at db.collection.InsertOne().
{
//code for initialization
//for localhost connection there is no need to specify the db server url and port.
var client = new MongoClient("mongodb://localhost:27017/");
var db = client.GetDatabase("TestDb");
Collection = db.GetCollection<T>("testCollection");
}
//Code for db operations
{
//The connection happens here.
var collection = db.Collection;
//Your find operation
var model = collection.Find(Builders<Model>.Filter.Empty).ToList();
//Your insert operation
collection.InsertOne(Model);
}
I found this out after I stopped my mongod server and debugged the code with breakpoint. Initialization happened smoothly but error was thrown at db operation.
Hope this helps.

MongoDB connection over SSL in Play Framework

I am using Play 1.2.5, MongoDB and Morphia module 1.2.9 in my application.
To create a secure and encrypted connection to the db, I installed MongoDB by enabling SSL using the follwoing links
http://docs.mongodb.org/manual/administration/ssl/
http://www.mongodb.org/about/tutorial/build-mongodb-on-linux/
Now I'm able to connect to the mongo shell using mongo --ssl also able to verify whether MongoDB is running or not using https://mylocalhost.com:27017/
But after enabling SSL in MongoDB, I am not able to connect to it through my play application.
Following are the lines I used in the application.conf to connect to the db
morphia.db.host=localhost
morphia.db.port=27017
morphia.db.db=test
Is there any configurations available to connect over SSL?
I did some googling and I am not able to find any solutions. Please help me over this?
Thanks in advance.
Morphia module does not support ssl connection for the moment. And I am not sure morphia library support it. Please create an issue on github to track this requirement: https://github.com/greenlaw110/play-morphia/issues?state=open
I use spring-data and came up against the same issue. With spring-data i was able to construct a Mongo object myself and passes it as a constructor param. Morphia might have the same mechanism. The key is:
options.socketFactory = SSLSocketFactory.getDefault();
After that, make sure you install the SSL public key into your key store and it should work.
public class MongoFactory {
public Mongo buildMongo (String replicaSet, boolean slaveOk, int writeNumber , int connectionsPerHost, boolean useSSL) throws UnknownHostException{
ServerAddress addr = new ServerAddress();
List<ServerAddress> addresses = new ArrayList<ServerAddress>();
int port =0;
String host = new String();
if ( replicaSet == null )
throw new UnknownHostException("Please provide hostname");
replicaSet = replicaSet.trim();
if ( replicaSet.length() == 0 )
throw new UnknownHostException("Please provide hostname");
StringTokenizer tokens = new StringTokenizer(replicaSet, ",");
while(tokens.hasMoreTokens()){
String token = tokens.nextToken();
int idx = token.indexOf( ":" );
if ( idx > 0 ){
port = Integer.parseInt( token.substring( idx + 1 ) );
host = token.substring( 0 , idx ).trim();
}
addr = new ServerAddress(host.trim(), port);
addresses.add(addr);
}
MongoOptions options = new MongoOptions();
options.autoConnectRetry = true;
if (useSSL){
options.socketFactory = SSLSocketFactory.getDefault();
}
options.connectionsPerHost=connectionsPerHost;
options.w=writeNumber;
options.fsync=false;
options.wtimeout=5000;
options.connectTimeout=5000;
options.autoConnectRetry=true;
options.socketKeepAlive=true;
Mongo m = new Mongo(addresses, options);
if(slaveOk){
m.setReadPreference(ReadPreference.SECONDARY);
}
return m;
}
}

Check if mongodb database exists?

Is there a possibility to check if a mongo database allready exists?
Yes, you can get the list of existing databases. From the Java driver you could do something like this to get the database names on a mongod server running on localhost
Mongo mongo = new Mongo( "127.0.0.1", 27017 );
List<String> databaseNames = mongo.getDatabaseNames();
This is equivalent to the mongo shell "show dbs" command. I am sure similar methods exist in all of the drivers.
From the shell, if you want to explicitely check that a DB exists:
db.getMongo().getDBNames().indexOf("mydb");
Will return '-1' if "mydb" does not exist.
To use this from the shell:
if [ $(mongo localhost:27017 --eval 'db.getMongo().getDBNames().indexOf("mydb")' --quiet) -lt 0 ]; then
echo "mydb does not exist"
else
echo "mydb exists"
fi
For anyone who comes here because the method getDatabaseNames(); is depreciated / not available, here is the new way to get the list of existing databases:
MongoClient mongoClient = new MongoClient();
MongoCursor<String> dbsCursor = mongoClient.listDatabaseNames().iterator();
while(dbsCursor.hasNext()) {
System.out.println(dbsCursor.next());
}
Here is a method that validates if the database is found:
public Boolean databaseFound(String databaseName){
MongoClient mongoClient = new MongoClient(); //Maybe replace it with an already existing client
MongoCursor<String> dbsCursor = mongoClient.listDatabaseNames().iterator();
while(dbsCursor.hasNext()) {
if(dbsCursor.next().equals(databaseName))
return true;
}
return false;
}
in python using Pymongo
from pymongo import MongoClient
db_name = "foo"
conn = MongoClient('mongodb://localhost,localhost:27017')
db = self.conn[str(db_name)]
if bool(db_name in conn.database_names()):
collection.drop()
using MongoDb c# Driver 2.4
private bool DatabaseExists(string database)
{
// _client is IMongoClient
var dbList = _client.ListDatabases().ToList().Select(db => db.GetValue("name").AsString);
return dbList.Contains(database);
}
usage:
if (!DatabaseExists("FooDb")
{
// create and seed db
}
I'd like to add a C# version. I'm using the MongoDB.Driver 2.2.2.
static bool DatabaseExists(string connectionString)
{
var mongoUri = new MongoUrl(connectionString);
var client = new MongoClient(mongoUri);
var dbList = Enumerate(client.ListDatabases()).Select(db => db.GetValue("name").AsString);
return dbList.Contains(mongoUri.DatabaseName);
}
static IEnumerable<BsonDocument> Enumerate(IAsyncCursor<BsonDocument> docs)
{
while (docs.MoveNext())
{
foreach (var item in docs.Current)
{
yield return item;
}
}
}
Try this, it worked for me (on Mac OSx)
MongoClient mongoClient = new MongoClient("localhost");
/** **/
boolean dbExist =
mongoClient.listDatabaseNames().
into(new ArrayList<String>()).contains("TEST");
System.out.print(dbExist);
The PyMongo example above didn't work for me, so I rewrote it using the more standard list_databases() method to the MongoClient library:
from pymongo import MongoClient
db_name = "foo"
conn = MongoClient('mongodb://localhost,localhost:27017')
if bool(db_name in conn.list_databases()):
print true # or return true here
else:
print false # or return false here
In my case, I could not use listDatabaseNames, because my user did not have the rights to call this function. Instead, I just assume that it exists and call a method on this database, which will fail if it does not exist or if rights are missing.
Demo C# code:
/// <summary>
/// Tests the connection to the MongoDB server, and if the database already exists.
/// If not or an error is detected, an exception is thrown.
/// </summary>
public static void TestConnection(string mongoUrl, string mongoDatabase) {
var client = new MongoClient(mongoUrl);
var database = client.GetDatabase(mongoDatabase);
try {
// Try to perform an action on this database; will fail if it does not exist
database.ListCollections();
}
catch {
throw new Exception("Connection established, " +
"but database does not exist (or missing rights): " + mongoDatabase);
}
}
I searched for how to list database names in golang and accidentially found this page. Looks like no one has provided ways to check if specific database name exists.
Assume that you are using MongoDB Go Driver, here is an approach
// client type is *mongo.Client
dbNames, err := client.ListDatabaseNames(context.Background(), bson.D{{Key: "name", Value: "YOUR-DB-NAME"}})
"dbNames" contains list of all databases in mongo server.
Second parameter is a filter, in this case, it only allows database with name == "YOUR-DB-NAME". Thus, dbNames will be empty if "YOUR-DB-NAME" is not exist.

How do I find the current version of a SQL Server data-tier application?

We are using a SQL Server Data-tier application (dacpac or DAC pack) and I'm having a hard time finding the current version of the database.
Is there a way to obtain the current version using any of these methods:
From within SQL Server Management Studio
Via a SQL statement
Programmatically using .NET code
From within SQL Server Management Studio
From http://msdn.microsoft.com/en-us/library/ee210574.aspx
To view the details of a DAC deployed to an instance of the Database Engine:
Select the View/Object Explorer menu.
Connect to the instance of the from the Object Explorer pane.
Select the View/Object Explorer Details menu.
Select the server node in Object Explorer that maps to the instance, and then navigate to the Management\Data-tier Applications node.
The list view in the top pane of the details page lists each DAC deployed to the instance of the Database Engine. Select a DAC to display the information in the detail pane at the bottom of the page.
The right-click menu of the Data-tier Applications node is also used to deploy a new DAC or delete an existing DAC.
Via a SQL statement
SELECT instance_name, type_version FROM msdb.dbo.sysdac_instances
Via a SQL statement on Azure
SELECT instance_name, type_version FROM master.dbo.sysdac_instances
Programmatically using .NET code
Note that in DacFx 3.0 this is no longer valid. See my other answer for a way to do it.
C#
ServerConnection serverConnection;
string databaseName;
// Establish a connection to the SQL Server instance.
using (SqlConnection sqlConnection =
new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
serverConnection = new ServerConnection(sqlConnection);
serverConnection.Connect();
// Assumes default database in connection string is the database we are trying to query.
databaseName = sqlConnection.Database;
}
// Get the DAC info.
DacStore dacstore = new DacStore(serverConnection);
var dacInstance = dacstore.DacInstances[databaseName];
System.Diagnostics.Debug.Print("Database {0} has Dac pack version {1}.", databaseName, dacInstance.Type.Version);
VB.NET
Dim serverConnection As ServerConnection
Dim databaseName As String
' Establish a connection to the SQL Server instance.
Using sqlConnection As New SqlConnection(ConfigurationManager.ConnectionStrings("DefaultConnection").ConnectionString)
serverConnection = New ServerConnection(sqlConnection)
serverConnection.Connect()
' Assumes default database in connection string is the database we are trying to query.
databaseName = sqlConnection.Database
End Using
' Get the DAC info.
Dim dacstore As New DacStore(serverConnection)
Dim dacInstance = dacstore.DacInstances(databaseName)
System.Diagnostics.Debug.Print("Database {0} has Dac pack version {1}.", databaseName, dacInstance.Type.Version)
In DacFx 3.0 the DacStore is no longer available. To get the version from C# code you need to query the database. Here's an example:
using System;
using System.Data;
using System.Data.SqlClient;
class Program
{
static void Main()
{
try
{
string version = GetDatabaseVersion(#"Initial Catalog=xxx;Data Source=yyy;Integrated Security=True;Pooling=False", false);
Console.WriteLine("Database has DAC pack version {0}.", version);
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
Console.WriteLine();
Console.ResetColor();
}
Console.WriteLine("Press any key to exit");
Console.ReadKey(true);
}
/// <summary>
/// Gets the database version.
/// </summary>
/// <param name="connectionString">The connection string of database to query.</param>
/// <param name="isAzure">True if we are querying an Azure database.</param>
/// <returns>DAC pack version</returns>
private static string GetDatabaseVersion(string connectionString, bool isAzure)
{
var connectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
string instanceName = connectionStringBuilder.InitialCatalog;
string databaseToQuery = "msdb";
if (isAzure)
{
// On Azure we must be connected to the master database to query sysdac_instances
connectionStringBuilder.InitialCatalog = "Master";
databaseToQuery = "master";
}
string query = String.Format("select type_version from {0}.dbo.sysdac_instances WHERE instance_name = '{1}'", databaseToQuery, instanceName);
using (var connection = new SqlConnection(connectionStringBuilder.ConnectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
command.CommandText = query;
command.CommandTimeout = 15;
command.CommandType = CommandType.Text;
var version = (string)command.ExecuteScalar();
return version;
}
}
}