Neo4j Driver for .NET Readonly mode not working - c#

I have problem with Neo4j Driver for .NET. To execute query, i use session with ReadOnly mode and Read transaction, but still i can modify graph via query like: Match (n) where Id(n) = 123 set n.foo = 33 return n; My code:
using (var session = Driver.Session(AccessMode.Read))
{
session.ReadTransaction(tx =>
{
try
{
var queryResult = tx.Run(job);
}
catch (Exception ex)
{
errorMessage = ex.Message;
}
});
}
Why is possible? How resolve this problem?

The AccessMode.Read define the type of the session, and this is used only when you are on a cluster mode, to perform session's transactions on a replica server and not on a core server.
It doesn't not tell that your session is a readonly one.
To have a pure read only access, you need to connect to Neo4j with a read only user.

Related

How to use Ignite Cache TextQuery in .Net Application

I am using Apache Ignite v2.7.6.And I have a .Net core ClientServer Ignite App.
I am trying to read/search text from the Person Model field Payload marked with QueryTextField.
TextQuery Ignite Docs.
Person Model:
public class Person: IConstructionCacheStore
{
[QueryTextField]
public string Payload { get; set; }
}
Code:
using (IIgniteClient client = Ignition.StartClient(this._igniteClientConfiguration))
{
//get cache config
var cache = client.GetCache<string, IConstructionCacheStore>(cacheName);
try
{
// Query for all people with "Master Degree" in their resumes.
var cursor = cache.Query(new TextQuery("Person", "Master Degree"));//Error
// Iterate over results. Using 'foreach' loop will close the cursor automatically.
foreach (var cacheEntry in cursor)
Console.WriteLine(cacheEntry.Value);
}
catch (Exception ex)
{
throw;
}
}
But I am getting a compile-time error at cache.Query(new TextQuery("Person", "Master Degree"));
like
Error CS1503 Argument 1: cannot convert from
'Apache.Ignite.Core.Cache.Query.TextQuery' to
'Apache.Ignite.Core.Cache.Query.ScanQuery<string,
ConstructionModels.IConstructionCacheStore>'
is TextQuery support in .Net?
How to solve above error?
Thanks.
TextQuery is not supported in Ignite thin clients:
Use thick client instead (.NET thick client supports TextQuery)
Use Services or Compute as a workaround (wrap TextQuery call in a Service or Compute Task, use thin client to call the service or the task)

Catch MongoAuthenticationException in Mongo .NET 2.0 Driver

I'm doing MongoDB project based on .NET 2.0 driver which involves authentication to MongoDB. There is a example code for what i'm doing:
public static bool createConneciton(string login, SecureString pass, string authDB) {
var settings = new MongoClientSettings {
Credentials = new[] {
MongoCredential.CreateCredential(authDB, login, pass)
},
Server = new MongoServerAddress("my.mongodb.server", 27017)
};
mongoClient = new MongoClient(settings);
return true;
}
if (Mongo.createConneciton(textBoxUsername.Text, pass, textBoxAuthDatabase.Text))
Task<BsonDocument> results = Mongo.getNodeStats();
public static async Task<BsonDocument> getNodeStats() {
try {
var db = Mongo.mongoClient.GetDatabase("admin");
var command = new BsonDocument {
{"serverStatus",1}
};
BsonDocument result = await db.RunCommandAsync<BsonDocument>(command).ConfigureAwait(false);
return result;
}
catch (Exception ex)
{
Logging.Log(ex);
return null;
}
}
Main problem i encountered so far is processing user's credentials. Because all operations are lazy and connection opens only on execution in getNodeStats() method. So if user types wrong credentials, he is going to wait for 30 seconds because instead of MongoDB.AuthenticationException or even MongoDB.ConnectionException method going to though only System.Timeout exception. If you look though text of exception that is quite obvious that both are rised but not catched.
"MongoDB.Driver.MongoConnectionException: An exception occurred while opening a connection to the server. ---> MongoDB.Driver.MongoAuthenticationException: Unable to authenticate using sasl protocol mechanism SCRAM-SHA-1
My first thought was to force open connection to check for credentials as soon as user typed them and hit connect button rather then waiting for any command to be executed, but apparently MongoClient class does not have .Open() method anymore. So if it does not seem to be possible i at least would like to catch AuthenticationException without need to wait for timeout, but out of ideas where should i try and catch it.
You cannot connect mongodb using MongoCredential.CreateCredential.You have to use MongoCredential.CreateMongoCRCredential method to connect the db. Because the former credential use SCRAM-SHA-1 mechanism to connect db, in .NET which will fail. And the reason I have not make clear.
Using MongoCredential.CreateMongoCRCredential, you have change "authSchema" setting in mongodb. You can refer to MongoDB-CR Authentication failed

Database locked issue while Inserting in same table the Array of more than 1000 records by multiple client

I am facing the big issue. I have created the service stack web services in C# DotNet and Database is SQLite (v4.0.30319). My System hang / Database locked issue, some time SQlite database file also corrupted while inserting/ updating the database table by number of clients (more than one connection). All are update the same table same time. Whle One is updating other try to connect than the system hang. I have tried all the ways but not able to resolve this issue.
How can I force that One One client can update the table at one time other clients can readonly mode.
My code as below
public bool CreateAnother2(LTHR record)
{
public IDbConnection Db { get; private set; }
OrmLiteConnectionFactory factory = new OrmLiteConnectionFactory("Data Source= C:/Database/db.sqlite;Integrated Security=True;User Instance=True", ServiceStack.OrmLite.Sqlite.SqliteOrmLiteDialectProvider.Instance);
try
{
using (Db = factory.OpenDbConnection())
{
using (var trans = Db.BeginTransaction()
{
// If no error insert data
var id = (int)Db.Insert(record, selectIdentity: true);
trans.Commit();
Db.Close();
return true;
}
}
}
catch (Exception ex)
{
if (Db.State == ConnectionState.Open)
{
Db.Close();
}
}
finally
{
if (Db.State == ConnectionState.Open)
{
Db.Close();
}
}
}
Sqlite is not meant to be used concurrently by multiple clients. That is your application runnning on multiple machines, or multiple applications on the same machine accessing the same shared database-file.
There are other solutions for that use case. (think mysql, postgress, Sqlserver, Oracle ea.).
If your application uses multiple connections to the database from one application but on different threads make sure that you open the database in serialized mode.
https://www.sqlite.org/threadsafe.html

Using SQL Server application locks to solve locking requirements

I have a large application based on Dynamics CRM 2011 that in various places has code that must query for a record based upon some criteria and create it if it doesn't exist else update it.
An example of the kind of thing I am talking about would be similar to this:
stk_balance record = context.stk_balanceSet.FirstOrDefault(x => x.stk_key == id);
if(record == null)
{
record = new stk_balance();
record.Id = Guid.NewGuid();
record.stk_value = 100;
context.AddObject(record);
}
else
{
record.stk_value += 100;
context.UpdateObject(record);
}
context.SaveChanges();
In terms of CRM 2011 implementation (although not strictly relevant to this question) the code could be triggered from synchronous or asynchronous plugins. The issue is that the code is not thread safe, between checking if the record exists and creating it if it doesn't, another thread could come in and do the same thing first resulting in duplicate records.
Normal locking methods are not reliable due to the architecture of the system, various services using multiple threads could all be using the same code, and these multiple services are also load balanced across multiple machines.
In trying to find a solution to this problem that doesn't add massive amounts of extra complexity and doesn't compromise the idea of not having a single point of failure or a single point where a bottleneck could occur I came across the idea of using SQL Server application locks.
I came up with the following class:
public class SQLLock : IDisposable
{
//Lock constants
private const string _lockMode = "Exclusive";
private const string _lockOwner = "Transaction";
private const string _lockDbPrincipal = "public";
//Variable for storing the connection passed to the constructor
private SqlConnection _connection;
//Variable for storing the name of the Application Lock created in SQL
private string _lockName;
//Variable for storing the timeout value of the lock
private int _lockTimeout;
//Variable for storing the SQL Transaction containing the lock
private SqlTransaction _transaction;
//Variable for storing if the lock was created ok
private bool _lockCreated = false;
public SQLLock (string lockName, int lockTimeout = 180000)
{
_connection = Connection.GetMasterDbConnection();
_lockName = lockName;
_lockTimeout = lockTimeout;
//Create the Application Lock
CreateLock();
}
public void Dispose()
{
//Release the Application Lock if it was created
if (_lockCreated)
{
ReleaseLock();
}
_connection.Close();
_connection.Dispose();
}
private void CreateLock()
{
_transaction = _connection.BeginTransaction();
using (SqlCommand createCmd = _connection.CreateCommand())
{
createCmd.Transaction = _transaction;
createCmd.CommandType = System.Data.CommandType.Text;
StringBuilder sbCreateCommand = new StringBuilder();
sbCreateCommand.AppendLine("DECLARE #res INT");
sbCreateCommand.AppendLine("EXEC #res = sp_getapplock");
sbCreateCommand.Append("#Resource = '").Append(_lockName).AppendLine("',");
sbCreateCommand.Append("#LockMode = '").Append(_lockMode).AppendLine("',");
sbCreateCommand.Append("#LockOwner = '").Append(_lockOwner).AppendLine("',");
sbCreateCommand.Append("#LockTimeout = ").Append(_lockTimeout).AppendLine(",");
sbCreateCommand.Append("#DbPrincipal = '").Append(_lockDbPrincipal).AppendLine("'");
sbCreateCommand.AppendLine("IF #res NOT IN (0, 1)");
sbCreateCommand.AppendLine("BEGIN");
sbCreateCommand.AppendLine("RAISERROR ( 'Unable to acquire Lock', 16, 1 )");
sbCreateCommand.AppendLine("END");
createCmd.CommandText = sbCreateCommand.ToString();
try
{
createCmd.ExecuteNonQuery();
_lockCreated = true;
}
catch (Exception ex)
{
_transaction.Rollback();
throw new Exception(string.Format("Unable to get SQL Application Lock on '{0}'", _lockName), ex);
}
}
}
private void ReleaseLock()
{
using (SqlCommand releaseCmd = _connection.CreateCommand())
{
releaseCmd.Transaction = _transaction;
releaseCmd.CommandType = System.Data.CommandType.StoredProcedure;
releaseCmd.CommandText = "sp_releaseapplock";
releaseCmd.Parameters.AddWithValue("#Resource", _lockName);
releaseCmd.Parameters.AddWithValue("#LockOwner", _lockOwner);
releaseCmd.Parameters.AddWithValue("#DbPrincipal", _lockDbPrincipal);
try
{
releaseCmd.ExecuteNonQuery();
}
catch {}
}
_transaction.Commit();
}
}
I would use this in my code to create a SQL Server application lock using the unique key I am querying for as the lock name like this
using (var sqlLock = new SQLLock(id))
{
//Code to check for and create or update record here
}
Now this approach seems to work, however I am by no means any kind of SQL Server expert and am wary about putting this anywhere near production code.
My question really has 3 parts
1. Is this a really bad idea because of something I haven't considered?
Are SQL Server application locks completely unsuitable for this purpose?
Is there a maximum number of application locks (with different names) you can have at a time?
Are there performance considerations if a potentially large number of locks are created?
What else could be an issue with the general approach?
2. Is the solution actually implemented above any good?
If SQL Server application locks are usable like this, have I actually used them properly?
Is there a better way of using SQL Server to achieve the same result?
In the code above I am getting a connection to the Master database and creating the locks in there. Does that potentially cause other issues? Should I create the locks in a different database?
3. Is there a completely alternative approach that could be used that doesn't use SQL Server application locks?
I can't use stored procedures to create and update the record (unsupported in CRM 2011).
I don't want to add a single point of failure.
You can do this much easier.
//make sure your plugin runs within a transaction, this is the case for stage 20 and 40
//you can check this with IExecutionContext.IsInTransaction
//works not with offline plugins but works within CRM Online (Cloud) and its fully supported
//also works on transaction rollback
var lockUpdateEntity = new dummy_lock_entity(); //simple technical entity with as many rows as different lock barriers you need
lockUpdateEntity.Id = Guid.parse("well known guid"); //well known guid for this barrier
lockUpdateEntity.dummy_field=Guid.NewGuid(); //just update/change a field to create a lock, no matter of its content
//--------------- this is untested by me, i use the next one
context.UpdateObject(lockUpdateEntity);
context.SaveChanges();
//---------------
//OR
//--------------- i use this one, but you need a reference to your OrganizationService
OrganizationService.Update(lockUpdateEntity);
//---------------
//threads wait here if they have no lock for dummy_lock_entity with "well known guid"
stk_balance record = context.stk_balanceSet.FirstOrDefault(x => x.stk_key == id);
if(record == null)
{
record = new stk_balance();
//record.Id = Guid.NewGuid(); //not needed
record.stk_value = 100;
context.AddObject(record);
}
else
{
record.stk_value += 100;
context.UpdateObject(record);
}
context.SaveChanges();
//let the pipeline flow and the transaction complete ...
For more background info refer to http://www.crmsoftwareblog.com/2012/01/implementing-robust-microsoft-dynamics-crm-2011-auto-numbering-using-transactions/

Test if MongoDB server is part of a replica set at run time

I have the same software deployed in multiple environments, some use a MongoDB replica set, and some use a single server. There are certain update operations where I use WriteConcern.WMajority, but this throws an exception if the server is not part of a replica set.
I'm looking for a way to ask the server if it is part of a replica set, so I will know if it is safe to use WriteConcern.WMajority. My attempt was this:
string connStr = System.Configuration.ConfigurationManager
.ConnectionStrings["connStrName"].ConnectionString;
var server = new MongoDB.Driver.MongoClient(connStr).GetServer();
bool isReplicaSet = server.GetDatabase("admin")
.RunCommand("replSetGetStatus").Ok;
But this throws MongoDB.Driver.MongoCommandException: Command 'replSetGetStatus' failed: not running with --replSet (response: { "ok" : 0.0, "errmsg" : "not running with --replSet" }). Is catching this exception my best option?
public bool IsPartOfReplicaSet(string connectionString)
{
var result = new MongoClient(connectionString)
.GetServer()
.GetDatabase("admin")
.RunCommand("getCmdLineOpts")
.Response["parsed"] as BsonDocument;
return result.Contains("replSet");
}

Categories

Resources