I am building a transport agent for Microsoft Exchange server. The logic I have implemented so far works. Now, I want to store some of the variables in DB. I have opted for a repository pattern and when I try to extract a connection string from App.Config file I am receiving a NullReference Exception:
public class ConfigRepository : IConfigRepository, IDisposable
{
private string configString = System.Configuration.ConfigurationManager.ConnectionStrings["citadelEAPEntities"].ConnectionString;
// private string configString = "..."; here I tried to write the string directly .
private string configValProc = "[dbo].[GetConfigValue]";
private SqlConnection connection;
public ConfigRepository()
{
connection = new SqlConnection(configString);
}
// other logic and implementation of interfaces
}
The same class is implemented in a test console app, which works fine (with the same connection string stored in the same manner in the app.config file).
I cannot understand the reason for this exception. The transporter agent class instantiates a ConfigRepository class within a 'using' statement and the moment it reaches the constructor function upon the initialization of the connection string variable via config manager an exception gets thrown. Obviously when I use the connection string in a hard coded manner everything works just fine.
Is the transporter agent assembly somehow limited while referencing other assemblies (such as System.Configuration) ? Just weird.
Transport Agents run under the security context of NetworkService so its most likely that it doesn't have enough rights to load the assembly from the location your referencing it from. If you use something like process monitor https://learn.microsoft.com/en-us/sysinternals/downloads/procmon your should be able track the process etc.
Related
I'm fairly certain I'm either doing something wrong, or understanding something wrong. It's hard to give a piece of code to show my problem, so I'm going to try explaining my scenario, with the outcome.
I'm starting up several instances of a DLL, in the same console application, but in it's own app domain. I then generated a Guid.NewGuid() that I assign to a class in the instance, and set the application's folder to a new folder. This works great so far. I can see everything works great, and my instances are seperated. However... when I started changing my app's folder to the same name as the unique GUID generated for that class I started picking up anomolies.
It works fine, when I instantiate the new instances slowly, but when I hammer new ones in, the application started picking up data in its folder, when it started up. After some investigation, I found that its because that folder already exist, due to that GUID already being instantiated. On further investigation, I can see that the machine takes a bit of a pause, and then continues to generated the new instances, all with the same GUID.
I understand that the GUID generating algorithm uses the MAC as part of it, but I was under the impression that even if the same machine, at the same exact moment generates two GUIDs, it would still be unique.
Am I correct in that statement? Where am I wrong?
Code :
Guid guid = Guid.NewGuid();
string myFolder = Path.Combine(baseFolder, guid.ToString());
AppDomain ad = AppDomain.CurrentDomain;
Console.WriteLine($"{ad.Id} - {guid.ToString()}");
string newHiveDll = Path.Combine(myFolder, "HiveDriveLibrary.dll");
if (!Directory.Exists(myFolder))
{
Directory.CreateDirectory(myFolder);
}
if (!File.Exists(newHiveDll))
{
File.Copy(hiveDll, newHiveDll);
}
Directory.SetCurrentDirectory(myFolder);
var client = ServiceHelper.CreateServiceClient(serviceURL);
ElementConfig config = new ElementConfig();
ElementConfig fromFile = ElementConfigManager.GetElementConfig();
if (fromFile == null)
{
config.ElementGUID = guid;
config.LocalServiceURL = serviceURL;
config.RegisterURL = registerServiceURL;
}
else
{
config = fromFile;
}
Directory.SetCurrentDirectory is a thin wrapper atop the Kernel 32 function SetCurrentDirectory.
Unfortunately, the .NET documentation writers didn't choose to copy the warning from the native function:
Multithreaded applications and shared library code should not use the SetCurrentDirectory function and should avoid using relative path names. The current directory state written by the SetCurrentDirectory function is stored as a global variable in each process, therefore multithreaded applications cannot reliably use this value without possible data corruption from other threads that may also be reading or setting this value
It's your reliance on this function that's creating the appearance that multiple threads have magically selected exactly the same GUID value.
I'm working on an app that has a live network database and a contingency local database, and it detects whether the live network db is accessible, and, if not, it times out after three seconds, changing the connectionstring to the local contingency database.
Following tips here on SO, I managed to alter the connectionstring on app.config during run time and reload the settings.
This is the method the app calls when a change on the connection string is needed:
public static void ChangeConnectionString(string connectionstring)
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var connectionStringsSection = (ConnectionStringsSection)config.GetSection("connectionStrings");
connectionStringsSection.ConnectionStrings[0].ConnectionString = connectionstring;
var connectionStrings = config.ConnectionStrings;
foreach (ConnectionStringSettings connectionString in connectionStrings.ConnectionStrings)
{
connectionString.ConnectionString = connectionstring;
}
config.Save();
ConfigurationManager.RefreshSection("connectionStrings");
PDV_WPF.Properties.Settings.Default.Save();
PDV_WPF.Properties.Settings.Default.Reload();
//Ensures the configuration is saved and reloaded.
FbConnection.ClearAllPools();
//Closes all currently open connections which might be using the old connection string.
Debug.WriteLine("==========Ran ChangeConnectionString");
Debug.WriteLine("==========FDBConnString is:");
Debug.WriteLine("==========" + PDV_WPF.Properties.Settings.Default.FDBConnString);
After I disconnect my computer form the network, whenever I check the current FDBConnString, it correctly points to the local contingency database. However, on the very next line, when it tries to run a query, I get the following exception:
Inner Exception 1:
IscException: Unable to complete network request to host "dbserver".
Inner Exception 2:
SocketException: Este host não é conhecido //(This host is unknown)
Full exception details: https://pastebin.com/3syLvsQf
It seems that, even after I successfully change the connection string, and successfully reload the application config file, it still tries to open a connection using the old connection string. Even if I call Debug to print the current Properties.Settings.Default.FDBConnString right on the line above the call for FbConnection.Open(), it shows the new string rather than the incorrect, old one.
Any insights on what might be going on?
I found what was the issue.
I am instancing a inherited table adapter from the generated xsd file. When I declare a table adapter on my class it also inherits the connection string stored on app.config at the time of declaration. So it doesn't matter if I change app.config, as the declared table adapter is already stuck with the previous connection string.
So, the solution was, rather than changing the connection string stored on app.config, I just had to change the connection string on the declared table adapter:
tB_STOCKTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.ContingencyDB;
tB_STK_PRODUCTTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.ContingencyDB;
or
tB_STOCKTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.NetworkDB;
tB_STK_PRODUCTTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.NetworkDB;
Both ContingencyDB and NetworkDB are strings stored on app.config as a user-scoped string, which can be changed via a given "Settings" window presented to the user.
New C# dev here, and I'm working on my first desktop application. I have a class set up that will do all of my SQL Server CE database work. Inside of my class, I have a few static strings set up that I am using to create the database, and I will use the same connection string to connect to the database.
private static string DBFileName = "engine.msbdb";
private static string DBPassword = "msb";
private static string DBConnectionString = string.Format("DataSource=\"{0}\"; Password='{1}'", DBFileName, DBPassword);
Now comes my question. In each of my methods that I have taking actions on my database, do I need to make a new connection in each of my methods? I can't necessarily create the connection in the constructor, because the database hasn't been created yet. How would I go about using the same connection in each of my methods so I don't have to rewrite all of the code each time I need to connect to the database? Do I simply write a private method that connects to the database and returns the database connection object? Just at a loss and can't figure out where to go from here. Sorry in advance if this question is a little confusing as I am still learning how this works.
Create a property in your class for the SqlCeConnection object. Call the Open() and Close() from each method in your class that needs it.
private SqlCeConnection conn { get; set; }
If your application is small scale desktop app, nothing wrong in creating SqlConnection as a private variable within each method. Try using it within a using statement for better disposing
using (SqlCeConnection connection = new SqlCeConnection(DBConnectionString)){
connection.Open();
using (SqlCeCommand cmd = new SqlCeCommand("SELECT * FROM Emp",connection))
{
}
}
Once you get a hang of C# and DotNet in general, try to read on Repository and UnitOfWork patterns. These patterns will help you to better isolate your data access logic
Hope this helps
I have a web service which invokes 2 different web methods.
One of the methods uses a SQL server connection and the other uses DB2.
The ODBC connection can talk to both a DB2 database and SQL server however the SQL has to be designed slightly differently for each method hence the option to switch the connection.
Right now I have a solution in place that is reading a string value from a text file stored on the server.
So if the string is SQL it uses the SQL connection string and ODBC uses the ODBC connection string.
Is there a more efficient way of doing this, without having to read the file in every time a web method is called as I am concerned that in the live environment, there will be bulk loads of data getting sent. So my concern is in the speed and performance of using this method.
Example of how I have implemented this -
String DBconSQL = "SQL-connection-string";
String DBconODBC = "ODBC-connection-string";
string connection = System.IO.File.ReadAllText(#"filePath");
[WebMethod]
public string stringRETURN(string connection)
{
if(connection == "SQL")
{
string con = "DBconSQL";
string sql = "SQL"
}
if(connection == "ODBC")
{
con = DBconODBC;
sql = "ODBC SQL";
}
//Do stuff here
}
Why don't you just store the value of each in memory after the first file read or just store them in the code.
i.e.
static class Globals
{
public static string DB2ConnStr = String.Empty;
public static string MSSQLStr = String.Empty;
}
You can read and write these from anywhere and they will persist as long as the server is up (i.e. the app is running in an app domain)
You should also (hopefully) be aware of the security concerns of storing plain text credentials either in code or text docs and (if this is for production) provide some form of encryption / security / reduce user permissions of the account that is being used to access the database ;)
This question may be redundant, but i could not totally understand how to do this.
I need to be able to, when the users Run my Winforms app, can search for the instance of SQL if the previous one are not available. I already have the check for the DB existence, and also made a dialog wich search for all the available instance, and bulding the connection string isn't a problem. The point here is that, I need to be able to everytime the users open the app it loads the CN from a external file, and if the external file doesn't exist or the instance isn't available, i can use the app in another instance (asuming, offcourse, that the required DB is in that Instance).
The point is that, i don't know how to Programmatically change Connection String, using LINQ in winforms.
Thanks in advance
You should be to pass the connection string to the DataContext constructor.
var db = new MyDataContext(myconnectionstring);
var someConnectionString = "This is my connection String";
using (var db = new SomeConcreteDataContext(someConnectionString)){
//...Do whatever...
}
A DataContext is created per 'unit of work'.
As ichiban says pass the required connection string into the constructor when creating the DC