How to use MongoDB connection globally - c#

My API is on .net mvc c# platform. I am using mongo DB to drop and store data the following way. It is not working properly when I try to drop and insert data concurrently. The connections are multiplying and the requests are not executed in the same order. How can I use the MongoDB in a global class with only one connection open? do give some reference to look into.
public static string DB= DBConnection.MongoDB;
public bool Insert(Data data)
{
try
{
var con = new MongoClient(DBConnection.ConnectionString);
var db = con.GetDatabase(DB);
db.InsertOne(data);
return true;
}
catch (Exception exception)
{
}
}
using System.Configuration;
namespace DataAccess.Implementations
{
internal class DBConnection
{
#region ConnectionString
public static string ConnectionString { get { return ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; } }
#endregion
#region Database
public static string MongoDB{ get { return ConfigurationManager.AppSettings["MongoDB"].ToString(); } }
#endregion
}
}

Try using a Singleton pattern:
https://social.msdn.microsoft.com/Forums/en-US/9e152212-2109-4d07-adbf-4ff0326c077b/how-to-establish-db-connection-using-singleton-pattern?forum=csharpgeneral
Singleton design pattern is preferred to get a DB Connection

Related

How to use local database in Xamarin.form?

I'm following a tutorial step by step to create a local database by using SQLite.net-PCL. However, when running the app, I tried to insert a data into the database, but it threw me a 'System.NullReferenceException'.
What I have done:
I'm only using SQLite.Net-TCL (1.2.1) package, and also added it into Android and iOS.
I noticed some tutorials saying that I should implement sqlite database on android and iOS, but I didn't find the tutorial is using this way, or maybe the IFileHelper interface has the same function?
I keep FileHelper interface in my Android folder
After debug, the database code passed. So the problem should happen when inserting data.
The exception happened at this line: if (person.ID != 0), and this line : await App.DB.SaveItemAsync(person);
Tutorial: https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/databases/
This is my database code:
using System.Threading.Tasks;
using System.Collections.Generic;
using System;
using SQLite;
namespace DatabaseDemo
{
public class Database
{
readonly SQLiteAsyncConnection _database;
public Database(string path)
{
_database = new SQLiteAsyncConnection(path);
_database.CreateTableAsync<Model>().Wait();
}
public Task<List<Model>> GetItemsAsync()
{
return _database.Table<Model>().ToListAsync();
}
public Task<int> SaveItemAsync(Model person)
{
if (person.ID != 0)
{
return _database.UpdateAsync(person);
}
else
{
return _database.InsertAsync(person);
}
}
}
}
This is my interface:
<StackLayout Margin="20" VerticalOptions="StartAndExpand">
<Label Text = "Name"/>
<Entry Text = "{Binding Name}" />
<Button Text = "Save" Clicked="OnSaveClicked" />
</StackLayout>
using Xamarin.Forms;
using System;
namespace DatabaseDemo
{
public partial class DatabaseDemoPage : ContentPage
{
public DatabaseDemoPage()
{
InitializeComponent();
}
async void OnSaveClicked(object sender, EventArgs e)
{
var person = (Model)BindingContext;
await App.DB.SaveItemAsync(person);
}
}
}
App.cs
using Xamarin.Forms;
namespace DatabaseDemo
{
public partial class App : Application
{
static Database database;
public static Database DB
{
get
{
if (database == null)
{
database = new Database(DependencyService.Get<IFileHelper>().GetLocalFilePath("db.db3"));
}
return database;
}
}
public App()
{
InitializeComponent();
MainPage = new DatabaseDemoPage();
}
}
}
I also created a public interface, and also created for Andriod and iOS.
using System;
namespace DatabaseDemo
{
public interface IFileHelper
{
string GetLocalFilePath(string filename);
}
}
You have to create Android side...
[assembly: Dependency(typeof(FileHelper))]
namespace Todo.Droid
{
public class FileHelper : IFileHelper
{
public string GetLocalFilePath(string filename)
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
return Path.Combine(path, filename);
}
}
}
Here all info
Once the interface has been defined, use the DependencyService to obtain an implementation and get a local file path (note that this interface has not been implemented yet). The following code gets an implementation in the App.Database property:
static TodoItemDatabase database;
public static TodoItemDatabase Database
{
get
{
if (database == null)
{
database = new TodoItemDatabase(DependencyService.Get<IFileHelper>().GetLocalFilePath("TodoSQLite.db3"));
}
return database;
}
}
The TodoItemDatabase constructor is shown below:
public TodoItemDatabase(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<TodoItem>().Wait();
}
This approach creates a single database connection that is kept open while the application runs, therefore avoiding the expense of opening and closing the database file each time a database operation is performed.
Solved by the following code:
public DatabaseDemoPage()
{
InitializeComponent();
this.BindingContext = new Model();
}

Strange behavior creating a new Database with Npgsql and Entity Framework

I'm trying to create a new database with npgsql and EF 6. This is my code:
using System.Data.Common;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Migrations;
using System.Data.Entity;
using System.Data.Entity.Migrations.Sql;
using Npgsql;
using NUnit.Framework;
namespace EntityFramework.PostgreSql.Test.IntegrationTests
{
[TestFixture]
public class PostgreSqlMigrationSqlGeneretorHistoryTest
{
private const string ConnectionString = "Server=127.0.0.1;Port=5432;Database=testEF6;User Id=postgres;Password=p0o9i8u7y6;CommandTimeout=20;Preload Reader = true;";
private const string ProviderName = "Npgsql";
[Test]
public void CreateNewDatabase()
{
const string cs = "Server=127.0.0.1;Port=5432;Database=testEFxx;User Id=postgres;Password=p0o9i8u7y6;CommandTimeout=20;Preload Reader = true;";
var db = new LocalPgContext(cs);
if (!db.Database.Exists())
db.Database.Create();
var exists = db.Database.Exists();
db.Database.Delete();
Assert.IsTrue(exists);
}
public class LocalPgContext : DbContext, IDbProviderFactoryResolver, IDbConnectionFactory
{
public LocalPgContext(string nameOrConnectionString) : base(nameOrConnectionString)
{
Database.SetInitializer(new CreateDatabaseIfNotExists<LocalPgContext>());
}
public DbProviderFactory ResolveProviderFactory(DbConnection connection)
{
return DbProviderFactories.GetFactory("Npgsql");
}
public DbConnection CreateConnection(string nameOrConnectionString)
{
return new NpgsqlConnection(nameOrConnectionString);
}
DbConnection IDbConnectionFactory.CreateConnection(string nameOrConnectionString)
{
return CreateConnection(nameOrConnectionString);
}
DbProviderFactory IDbProviderFactoryResolver.ResolveProviderFactory(DbConnection connection)
{
return new LocalPgProviderFactory();
}
}
public class LocalPgProviderFactory : DbProviderFactory
{
public override DbConnectionStringBuilder CreateConnectionStringBuilder()
{
return new NpgsqlConnectionStringBuilder(ConnectionString);
}
public override DbConnection CreateConnection()
{
return new NpgsqlConnection(ConnectionString);
}
}
}
}
The strange thing is that I create a new connection using Npgsql but when I'm executing if (!db.Database.Exists()) it try to create a connection using SqlServer provider. It tell me that it doesn't know the "port" attribute of the connection string because sql server haven't this attribute.
I'm thinking that it is looking for the default provider factory into the web.config file but not finding it, it set sql server as default provider.
I would like to set Npgsql as default provider without using a config file at all.
Npgsql add the support to delete or create the database from the 2.2.0 version (now is in beta 1)

Connecting to a SQL server using ADODB from a C# dll

I am writing a custom Connection class in C# for Excel to be able to connect to a SQL Server.
When I use SQLConnection from System.Data.SqlClient library I am able to establish a connection. The working code I've got:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Runtime.InteropServices;
namespace Test
{
[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid("6E8B9F68-FB6C-422F-9619-3BA6D5C24E84")]
public interface IConnection
{
bool Status { get; }
bool Open();
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("B280EAA4-CE11-43AD-BACD-723783BB3CF2")]
[ProgId("Test.Connection")]
public class Connection : IConnection
{
private bool status;
private SqlConnection conn;
private string connString = "Data Source=[server]; Initial Catalog=[initial]; User ID=[username]; Password=[password]";
public Connection()
{
}
public bool Status
{
get
{
return status;
}
}
public bool Open()
{
try
{
conn = new SqlConnection(connString);
conn.Open();
status = true;
return true;
}
catch(Exception e)
{
e.ToString();
return false;
}
}
}
}
And after adding the reference to Excel I am able to test the connection using a simple VBA code like this:
Sub TestConnection()
Dim conn As Test.Connection
Set conn = New Test.Connection
Debug.Print conn.Status
conn.Open
Debug.Print conn.Status
End Sub
It outputs:
False
True
So everything is fine. Now I would like to create custom Recordset class in my C# library so I decided to use an ADODB library and its RecordSetinstead of SqlDataReader as I am planning to work with some big chunks of data. So, I have modified my code to this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Runtime.InteropServices;
namespace Test
{
[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid("6E8B9F68-FB6C-422F-9619-3BA6D5C24E84")]
public interface IConnection
{
bool Status { get; }
bool Open();
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("B280EAA4-CE11-43AD-BACD-723783BB3CF2")]
[ProgId("Test.Connection")]
public class Connection : IConnection
{
private bool status;
private ADODB.Connection conn = new ADODB.Connection();
private string connString = "Data Source=[server]; Initial Catalog=[initial]; User ID=[username]; Password=[password]";
public Connection()
{
}
public bool Status
{
get
{
return status;
}
}
public bool Open()
{
try
{
conn.ConnectionString = connString;
conn.Open();
// conn.Open(connString, ["username"], ["password"], 0)
// what else can I try? is this where it actually fails?
status = true;
return true;
}
catch (Exception e)
{
e.ToString();
return false;
}
}
}
}
I also have added references to Microsoft ActiveX Data Objects 6.1 Library.
Now, when I am executing the VBA code it outputs:
0
0
But I was expecting 0 and 1. It seems to me like I am not properly connecting to the server ( credentials are the same i have just removed actual data from this code ).
I have tried to use different variations of the connection string, however it always returns 0 and 0. I have tried creating a new project with new GUIDs and also tried renaming the projects, classes, etc. nothing has worked. I am suspecting its the establishment of the connection but I am unsure how to debug a dll.
I have used link1, link2, link3, link4 for reference
Update:
I have wrote the exception to the file as TheKingDave suggested. This is the exception error message
System.Runtime.InteropServices.COMException (0x80004005):
[Microsoft][ODBC Driver Manager] Data source name not found and no
default driver specified at ADODB._Connection.Open(String
ConnectionString, String UserID, String Password, Int32 Options) at
TestADODB.Connection.Open() in c:\Users\administrator\Documents\Visual
Studio 2012\Projects\Test\Test\Connection.cs:line 49
The connection string is missing Provider=SQLOLEDB.
The ADODB.Connection needs to know what type of database it is connecting to.

Asynchronous insert in Azure Table

How to asynchronously save an entity to Windows Azure Table Service?
The code below works synchronously but raises an exception when trying to save asynchronously.
This statement:
context.BeginSaveChangesWithRetries(SaveChangesOptions.Batch,
(asyncResult => context.EndSaveChanges(asyncResult)), null);
Results in System.ArgumentException: "The current object did not originate the async result. Parameter name: asyncResult".
Additionally, what's the correct pattern for creating the service context when saving asynchronously? Should I create a separate context for each write operation? Is it too expensive (e.g. requiring a call over the network)?
TableStorageWriter.cs:
using System;
using System.Data.Services.Client;
using System.Diagnostics;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
namespace WorkerRole1
{
public class TableStorageWriter
{
private const string _tableName = "StorageTest";
private readonly CloudStorageAccount _storageAccount;
private CloudTableClient _tableClient;
public TableStorageWriter()
{
_storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
_tableClient = _storageAccount.CreateCloudTableClient();
_tableClient.CreateTableIfNotExist(_tableName);
}
public void Write(string message)
{
try
{
DateTime now = DateTime.UtcNow;
var entity = new StorageTestEntity
{
Message = message,
PartitionKey = string.Format("{0:yyyy-MM-dd}", now),
RowKey = string.Format("{0:HH:mm:ss.fff}-{1}", now, Guid.NewGuid())
};
// Should I get this context before each write? It is efficient?
TableServiceContext context = _tableClient.GetDataServiceContext();
context.AddObject(_tableName, entity);
// This statement works but it's synchronous
context.SaveChangesWithRetries();
// This attempt at saving asynchronously results in System.ArgumentException:
// The current object did not originate the async result. Parameter name: asyncResult
// context.BeginSaveChangesWithRetries(SaveChangesOptions.Batch,
// (asyncResult => context.EndSaveChanges(asyncResult)), null);
}
catch (StorageClientException e)
{
Debug.WriteLine("Error: {0}", e.Message);
Debug.WriteLine("Extended error info: {0} : {1}",
e.ExtendedErrorInformation.ErrorCode,
e.ExtendedErrorInformation.ErrorMessage);
}
}
}
internal class StorageTestEntity : TableServiceEntity
{
public string Message { get; set; }
}
}
Called from WorkerRole.cs:
using System.Net;
using System.Threading;
using Microsoft.WindowsAzure.ServiceRuntime;
using log4net;
namespace WorkerRole1
{
public class WorkerRole : RoleEntryPoint
{
public override void Run()
{
var storageWriter = new TableStorageWriter();
while (true)
{
Thread.Sleep(10000);
storageWriter.Write("Working...");
}
}
public override bool OnStart()
{
ServicePointManager.DefaultConnectionLimit = 12;
return base.OnStart();
}
}
}
Examples using Windows Azure SDK for .NET 1.8.
You should call EndSaveChangesWithRetries instead of EndSaveChanges, as otherwise the IAsyncResult object returned by BeginSaveChangesWithRetries cannot be used by EndSaveChanges. So, could you please try changing your End method call as below?
context.BeginSaveChangesWithRetries(SaveChangesOptions.Batch,
(asyncResult => context.EndSaveChangesWithRetries(asyncResult)),
null);
And for your other question, I would recommend creating a new TableServiceContext for each call, as DataServiceContext is not stateless (MSDN) and the way you implemented TableStorageWriter.Write with the asynchronous call might allow concurrent operations. Actually, in Storage Client Library 2.0, we explicitly prevented concurrent operations that uses a single TableServiceContext object. Moreover, creating a TableServiceContext does not result in a request to Azure Storage.

Unknown command error when using multithread to set redis

I am using the ServiceStack.Redis C# client to talk to Redis.
With few request everything is ok, but when I get LoadRunner to request it or use multi-threading to make requests, I get some errors that say I am using the wrong command.
I check the errors, and it seems that it cut off the command, or it mess up.
Here is my code, very simple. Has anyone come across this problem? The errors happen when I call the Push method using multi-threading.
public class ImpresstionQueueService : IQueueService<InsertImpressionRequest>
{
private string _queueName;
private string _host;
private static IRedisClient redisClient = new RedisClient(ConfigHost);
private static string ConfigHost
{
get
{
return ConfigurationManager.AppSettings.Get("redis_host");
}
}
private string Host
{
get
{
if (!string.IsNullOrEmpty(_host))
return _host;
else
{
return ConfigurationManager.AppSettings.Get("redis_host");
}
}
}
public ImpresstionQueueService(string queue_name)
{
this._queueName = queue_name;
}
public ImpresstionQueueService(string host, string queu_name)
{
this._queueName = queu_name;
this._host = host;
}
#region IQueueService<InsertImpressionRequest> Members
class testData
{
}
public int Push(InsertImpressionRequest value)
{
try
{
//using (var redisClient = new RedisClient(this.Host))
{
//ser
string ser_value = TypeSerializer.SerializeToString<InsertImpressionRequest>(value);
//push
redisClient.AddItemToList(this._queueName, ser_value);//here will be error
}
}
catch (Exception ex)
{
HLogger.GetLogger("RedisLogger").Error(ex.Message + ex.StackTrace);
}
//throw new NotImplementedException();
return 1;
}
public InsertImpressionRequest Pop()
{
InsertImpressionRequest request = null;
//using (var redisClient = new RedisClient(this.Host))
{
string pop_string_value = redisClient.PopItemFromList(this._queueName);
//deseri
if (pop_string_value != null)
{
request = TypeSerializer.DeserializeFromString<InsertImpressionRequest>(pop_string_value);
}
}
return request;
}
#endregion
}
You are probably using the same Redis connection simultaneously from multiple threads. Both threads could possibly send commands or wait for replies at the same time. When this happens, one thread receives data intended for the other thread. This causes your error.
If you use one Redis client per thread (instead of one client per ImpresstionQueueService), each thread can send commands at the same time without interfering with each other.
Alternatively, you can create a client just for the single request (which you commented out just above the error location). The disadvantage of this alternative is the overhead of a new connection every time (which might be large or small or unnoticeable).

Categories