How to set proper path to TNSNAMES file in C# application? - c#

I have a program in C# that use ODP.NET dlls:
oci.dll, ociw32.dll, Oracle.DataAccess.dll,
orannzsbb11.dll, oraocci11.dll, oraociicus11.dll,
OraOps11w.dll.
I've got 2 computers. First with whole ODAC package installed, and second without that package. But I have all required dlls in my exe directory, so ODAC is not a problem I think.
The difference between these computers is the path to the TNSNAMES file.
First: C:\app\OraHome_1\Network\admin\
Second: C:\Oracle\product\11.2.0\client_1\network\admin
On the first computer, the program works fine. But on the second one with the same connection string, I get the error:
cannot open connection (ORA-12154)
Using SQL Plus I can connect on both computers. How can I show my program the proper path to the tnsnames.ora file?

You can set the TNS_ADMIN environment variable programmatically. See this page for a step by step. That is if you wanted to change to a specific TNS_NAMES.ORA file. The Oracle Client must still be installed on the client machine.
From ConnectionStrings - without using TNS:
Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=MyHost)(PORT=MyPort))(CONNECT_DATA=(SERVICE_NAME=MyOracleSID)));User Id=myUsername;Password=myPassword;
EDIT: Added 3rd option
Please see this question which could aid you in finding the current location of the client's TNS_NAMES.ORA file - which you could open and modify if you wish (add your own connection if it doesn't exist)

You don't need to care about the path of your TNSNames file: it'll be automatically discovered by the library itself... once you have it installed. That's the key point: distributing the dll within your project is not enough. You need to install ODP.Net on the machine that need to use it: actually the installation simply create a few registry entry, and one of them point to the right oracle dir (in which the library can find out the tnsnames when needed).
Morover, as someone pointed out, you don't need a tnsnams file at all. You could write everything needed inside the connection string.
Here's one I use in my environment:
Data Source= (DESCRIPTION =
(ENABLE = BROKEN)
(ADDRESS_LIST =
(LOAD_BALANCE = ON)
(FAILOVER = ON)
(ADDRESS = (PROTOCOL = TCP)(Host =por10srv-a)(Port = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = por10.gruppo.autostrade.it)
(FAILOVER_MODE =
(TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 10)
(DELAY = 3)
)
)
);User ID=npa_collaudo;Password=npa_collaudo;

You don't need to install ODP.NET (or for that matter the Oracle Client) as you seem to have the required DLLs for a local distributable inline oracle client. In your case it's possible to have the TNSNAMES.ORA file located in the same folder as your executable and your specialised "inline oracle client" will pick it up from there. Otherwise the oracle client local to your application will try to pick it up from any client installed on the machine.

Related

C# application deployment issue with .mdf database

I am working on a C# database application for learning and I'm trying to deploy it on client machine and getting connection problem.
//NOTE: path and database variables have correct info because it works on my dev machine
"Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=" + path + "\\" + databaseName + ";Integrated Security=True"
I am using Install Shield for creating setup and tried Advance Installer also.
On the other test machine I have installed:
.Net Framework 4.5.2
SQLLocalDB.msi (x64 bit)
Lastly, I installed my deployed setup file and I was getting an Exception:
System.Data.SqlClient.SqlException (0x80131904). A network related or instance-specific error occured while establishing a connection to SQL server.
The server was not found or not accessible.
Localdatabase Runtime error occured.
I also tried these in Connection String: (found in similar question on stackoverflow)
localhost
localhost\\SQLExpress
.\\SQLExpress
But none of this work for me.
NOTE:
My LocalDB connection string is working on dev machine.
Using Visual Studio 2015 Enterprise
PS: What I am trying to learn is a way to create an installer which installs some per-requeisites like .Net Framework, LocalDB etc and can run database based application on client machines without installing SQL Server separately. I am not sure if the .mdf way is the good fit for this or not.
I would suggest you to use SQLite Database because the process and function are almost similar. And the deployment is super easy; it just requires few DLLs to make it work.
Guideline:
First you will need System.Data.SQLite library and then needs to add System.Data.SQLite.dll as a reference in your project. Keep in mind that SQLite.Interop.dll also needs to be in your executables directory but doesn’t need to be added as a reference in your project.
Moreover, if your application is targeting Any CPU it is likely that you will get an exception. So make sure to navigate to Project properties -> Build and set the Platform target to the bit version of the System.Data.SQLite.dll binary you have downloaded.
As you are beginner so here is the step by step guideline along with sample code.
Steps:
Navigate to: Tools > NuGet Package Manager > Manage NuGet Packages for Solution
Search For: SQLite
Select System.Data.SQLite (would be first result)
Click on Install
Import library
using System.Data.SQLite;
The connection is ready and here is the Sample Code:
System.Data.SQLite.SQLiteConnection.CreateFile("sqlite.db3");
using(System.Data.SQLite.SQLiteConnection conn = new System.Data.SQLite.SQLiteConnection("data source=sqlite.db3")){
using(System.Data.SQLite.SQLiteCommand cmd = new System.Data.SQLite.SQLiteCommand(conn)){
conn.Open();
cmd.CommandText = #"CREATE TABLE IF NOT EXISTS
[persons](
[id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[name] VARCHAR(50) NULL
)";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO [persons] (name) values('Atlas')";
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT * FROM [persons]";
using(System.Data.SQLite.SQLiteDataReader reader = cmd.ExecuteReader()){
while(reader.Read()){
MessageBox.Show(reader["name"].ToString());
}
conn.Close();
}
}
}
Tips:
always use try/catch block for database operations
If you don't prefer to use NuGet Package Manager then you can download library from here
Hope this helps! :)
Does one of these help?
Attach a database file on connect to a local SQL Server Express instance
Server=.\SQLExpress;AttachDbFilename=C:\MyFolder\MyDataFile.mdf;Database=dbname;
Trusted_Connection=Yes;
Attach a database file, located in the data directory, on connect to a local SQL Server Express instance
Server=.\SQLExpress;AttachDbFilename=|DataDirectory|mydbfile.mdf;Database=dbname;
Trusted_Connection=Yes;

.NET executables do not work after overwritten with new versions

I faced very strange behaviour - after I overwrite .NET exectables with new versions from network drive it cannot start.
When try to start from Windows Explorer it shows me following error:
[Window Title]
C:\Programs\zzz\clients.net\zzzNet.exe
[Content]
C:\Programs\zzz\clients.net\zzzNet.exe
The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log or use the command-line sxstrace.exe tool for more detail.
I tried to execute following commands:
SxsTrace Trace -logfile:SxsTrace.etl
SxStrace Parse -logfile:SxSTrace.etl -outfile:SxSTrace.txt
And got following result:
=================
Begin Activation Context Generation.
Input Parameter:
Flags = 0
ProcessorArchitecture = AMD64
CultureFallBacks = en-US;en;ru-RU;ru
ManifestPath = C:\Programs\zzz\clients.net\zzzNet.exe
AssemblyDirectory = C:\Programs\zzz\clients.net\
Application Config File = C:\Programs\zzz\clients.net\zzzNet.exe.Config
-----------------
INFO: Parsing Application Config File C:\Programs\zzz\clients.net\zzzNet.exe.Config.
INFO: Parsing Manifest File C:\Programs\zzz\clients.net\zzzNet.exe.
INFO: Manifest Definition Identity is (null).
ERROR: Line 0: XML Syntax error.
ERROR: Activation Context generation failed.
End Activation Context Generation.
It is quite simple .NET application (1 exe + 8 dll files). It was built for .NET 3.5 Client Profile.
I not defined any special "manifest" there. Just clicked "New Windows Forms Project" in Visual Studio and developed it.
Also app.config does not contain anything special - only primitive standard settings - appSettings and userSettings sections.
On PC where I developed it all is perfectly works. Problems only began when I copy these binaries to this particular VM and try to start.
Also please note - these executables were not installed in GAC or such, I just copied them into a folder on VM and started. And when it was 1st time all was working fine.
So, the problem pattern is following:
Copy .NET execuatbles to new VM (it is Win 7 x64), run it, all is working fine. Close it.
Build new version of .NET execuatbles on host PC, copy new .NET execuatbles to VM (with files overwriting).
Try to start - got mentioned problem.
After some shaman-style actions (like OS reboot, etc) it begin to work but why that happened at all?!
Why replacing .NET executables with new versions is causing SUCH HUGE PROBLEMS?!
Also the BIG QUESTION - is there any special procedure to replace .NET executables to keep them working? Because it is a new app development, I do not want lost so much time on every new executables installation. :-\
Could you please help? Because it looks completely weird!
Thank you in adance.
PS. I checked all VS projects - all they have PlatformTarget=AnyCPU. Also in run-time I can see ProcessType=MSIL (I show this info in AboutBox for application). So, there is no mix of x86/x64 binaries.
It seems that was related to mapped network drive behavior.
When I copied new files from network drive folder it copied wrong files - a strange random mess of new files and older ones (which were there before I updated them on VM host).
The scenario to make it working:
on VM: delete all files in a folder on network drive
on VM host: copy new files into a folder which is mapped as network drive on VM
on VM: copy files into target folder
on VM: run application - it works now
Weird thing. I remember I have seen something similar with Windows Explorer on Windows 2008 behaviour when copying updated win32 binaries.

Windows Setup: Dynamic Registry Keys/Values

A synopsis of my question:
Is it possible to use your own, custom variables (the way that you can use [TARGETDIR]) in the Registry screen of a Windows Setup project in VS2010? Specifically, I need to store my assembly's strong name and assembly version in the registry, in order to register a COM object on a machine without the installing user having admin rights.
I already tried using a custom action, and I'd rather not continue down that road if possible.
Here are the specifics, and what I've tried:
Recently, my employer started blindly removing all employees' admin rights from their machines.
I had created a COM-exposed C# class that I'd been using on a few of my workstations, which is no longer able to be registered, because I no longer have the appropriate permissions under HKEY_CLASSES_ROOT.
Through Googling, I found out how to register all of the appropriate keys under HKCU*, but now I'd like to implement this in my deployment project.
I understand how to use the Registry screen within Windows Setup, but there are custom keys/values that need to be stored (install folder, assembly strong name, version).
I could use a custom action, but ideally, I want Windows Setup to manage my registry settings, because (a) it's better than I am at automatically removing all the proper keys/values upon uninstall, (b) during the install, registry changes are transactional & rolled back upon install error, and (c) the logic for registry key install/removal/transactions is already written by Microsoft, and I won't have to rewrite it myself.
The project was in VS2008 until today, but I just upgraded it to VS2010, so perhaps something has changed between 2008 and 2010 that might allow this behavior.
So, rather than using a custom action, is there a better way to do this?
EDIT: I found this answer, which seems to suggest that you can access the Windows Install "Registry" table within your install project. I'm not sure how to do access it, though. In the past, I seem to recall that you could access the MSI databases from a special external tool (Orca), but I don't know if you can access these tables in your setup project.
EDIT 2: Ah, I may be on to something; perhaps a post-build event:
Use Orca to edit msi from command line?,
Examples of Database Queries Using SQL and Script,
WiRunSQL.vbs
* Run RegAsm twice - once with /codebase and once without; both times with the /regfile option. Then merge both files together (removing duplicates), and replace all HKCR references with HKCU\Software\Classes.
Yes, this can be done*.
First, create a Console executable that will be run as part of a post-build event of the Windows Setup project. This modifies the Registry table in the MSI file that has been built by VS2010.
Note: You must add a reference to "Microsoft Windows Installer Object Library" under COM, for the below code to compile.
using System;
using WindowsInstaller;
using System.Runtime.InteropServices;
using System.Reflection;
namespace Post_Setup_Scripting
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("Incorrect args.");
return;
}
//arg 1 - path to MSI
string PathToMSI = args[0];
//arg 2 - path to assembly
string PathToAssembly = args[1];
Type InstallerType;
WindowsInstaller.Installer Installer;
InstallerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
Installer = (WindowsInstaller.Installer)Activator.CreateInstance(InstallerType);
Assembly Assembly = Assembly.LoadFrom(PathToAssembly);
string AssemblyStrongName = Assembly.GetName().FullName;
string AssemblyVersion = Assembly.GetName().Version.ToString();
string SQL = "SELECT `Key`, `Name`, `Value` FROM `Registry`";
WindowsInstaller.Database Db = Installer.OpenDatabase(PathToMSI, WindowsInstaller.MsiOpenDatabaseMode.msiOpenDatabaseModeDirect);
WindowsInstaller.View View = Db.OpenView(SQL);
View.Execute();
WindowsInstaller.Record Rec = View.Fetch();
while (Rec != null)
{
for (int c = 0; c <= Rec.FieldCount; c++)
{
string Column = Rec.get_StringData(c);
Column = Column.Replace("[AssemblyVersion]", AssemblyVersion);
Column = Column.Replace("[AssemblyStrongName]", AssemblyStrongName);
Rec.set_StringData(c, Column);
View.Modify(MsiViewModify.msiViewModifyReplace, Rec);
Console.Write("{0}\t", Column);
Db.Commit();
}
Console.WriteLine();
Rec = View.Fetch();
}
View.Close();
GC.Collect();
Marshal.FinalReleaseComObject(Installer);
Console.ReadLine();
}
}
}
The "variables" that we are going to use in the Windows Setup Registry screen get replaced in these lines of the above code; this could be adapted to any items that are necessary.
string Column = Rec.get_StringData(c);
Column = Column.Replace("[AssemblyVersion]", AssemblyVersion);
Column = Column.Replace("[AssemblyStrongName]", AssemblyStrongName);
Second, create a .reg file that contains the registry keys you want to create upon install. In the code above, we modify the MSI database in the post-build by replacing all instances of [AssemblyVersion] with the assembly version, and [AssemblyStrongName] with the assembly's strong name.
[HKEY_CURRENT_USER\Software\Classes\Record\{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\[AssemblyVersion]]
"Class"="MyClass.MyClass"
"Assembly"="[AssemblyStrongName]"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="[TARGETDIR]MyClass.dll"
Third, import the .reg file into the Windows Setup registry screen in VS2010 by right-clicking "Registry On Target Machine", and clicking "Import".
Finally, call the post-build executable in the "PostBuildEvent" property of the setup project:
"C:\Path\To\Exe\Post-Setup Scripting.exe" [Path to MSI] [Path To DLL to extract strong name/version]
* This is a little different than using [TARGETDIR], because [TARGETDIR] gets resolved at install time, and these "variables" will get resolved at build time. For my solution, I needed to resolve at build time, because my version number increments with each build.

Firebird client installation

I'm trying to deploy my Application that uses a Firebird v2.5 database to a client machine.
I am trying to use a minimum installation, without the need to run any other installers. From what I gather, all I need to do is copy the "FBClient.dll" to the target application folder (which includes firebird database file). I have tried this and it still reports an error about not being able to find the correct .net data provider.
eg
C:\Program Files (x86)\MyApp\myApp.exe
C:\Program Files (x86)\MyApp\fbDatabase.fdb
C:\Program Files (x86)\MyApp\fbclient.dll
The error produced is:
Failed to find or load the registered .Net Framework Data Provider.
Also have copied, renamed and included fbclient.dll as fbembed.dll
I have also tried to copy a bunch of other files to the app directory, as well as placing fbclient.dll into the c:\, c:\windows, c:\windows\system.
I also tried installing the client installation, with no joy too.
Is there a way, that I can use the firebird database, without manually editing the machine.config files or using the gac and going through the hell that I went through to install firebird on the dev machine? I want an application that a user can install, not requiring that it be installed by a developer.
Please note, the application that I am writing is for a single machine, single user environment, who knows how to double click the install button, with the attention span of a gnat, that if required to do more than double click install and then press GO, will simply get bored and press the cancel, forget it button.
I add the file "FirebirdSql.Data.FirebirdClient.dll" to the application folder and I no longer get the Data provider error, instead I get the following
"Unable to complete network request to host \"DevMachine\"."
at FirebirdSql.Data.Client.Managed.Version10.GdsConnection.Connect()
at FirebirdSql.Data.FirebirdClient.ClientFactory.CreateManagedDatabase(FbConnectionString options)
at FirebirdSql.Data.FirebirdClient.ClientFactory.CreateDatabase(FbConnectionString options)
at FirebirdSql.Data.FirebirdClient.FbConnectionInternal.Connect()
I am trying to connect with the following
string file = #"C:\Program Files (x86)\MyApp\Test.FDB;";
FbConnection con = new FbConnection("User=SYSDBA;" + "Password=masterkey;" + "Database=" + file + "DataSource=Dev-VS-W7VM;" + "Port3050;" + "Dialect=3;" + "Charset=ISO8859_1;");
try
{
con.Open();
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
I have included FirebirdSql.Data.FirebirdClient in my project and installation folder (..\MyApp)
Thank you in advance.
You have to grap a zip and copy FirebirdSql.Data.FirebirdClient.dll to bin folder.
I wonder how you wrote your application that it works without the file (probably installed .msi) :)
You needed to install .net provider
http://www.firebirdsql.org/en/net-provider/
The database file resides next to your application's exe module. So, you need in local server running or embedded server in order to work with data. For embedded server a minimal set of files is (specifed relatively to an application folder):
\UDF (folder with UDF needed if any)
\Intl (with contents from FB installation)
fbembed.dll
firebird.msg
ib_util.dll
icudt30.dll
icuin30.dll
icuuc30.dll
Microsoft.VC80.CRT.manifest
msvcp80.dll
msvcr80.dll
for a full scale server (i.e. not an embedded) a list of files would be:
\UDF (folder with UDF needed if any)
\Intl (with contents from FB installation)
fbserver.exe or fb_inet_server.exe
fbclient.dll
firebird.msg
ib_util.dll
icudt30.dll
icuin30.dll
icuuc30.dll
Microsoft.VC80.CRT.manifest
msvcp80.dll
msvcr80.dll
security2.fdb
firebird.conf (if non default parameters used)
But then you would need in setting up service record for FB
or start it as an application before your application start.
Installation of the Firebird as a service could be done with
instsvc.exe utility. Appropriate commands:
instsvc install -s -a
instsvc start
Also you should take care of two things:
FileName must be a local file, not in a shared folder from another server.
Appending the firebird server IP before the filename. If you are running your app always in the firebird server, or you are using embeded fbclient.dll, than it should be like
FbConnection con = new FbConnection("User=SYSDBA;" + "Password=masterkey;" + "Database=localhost:" + file + "DataSource=Dev-VS-W7VM;" + "Port3050;" + "Dialect=3;" + "Charset=ISO8859_1;");
Some fbclient.dll version will allow you not to add localhost and still connect on local files, or use \\servername\c:\filename format instead of localhost:c:\filename, but it is deprecated and not supposed to work anymore (and can work depending on windows version).

How to connect and use Firebird db embedded server with Visual C# 2010

I was trying to use Firebird embedded server with Microsoft Visual C# 2010.
so here is what I done till now:
Downloaded Firebird .Net Data Provider (Firebird Client v2.5.2).
Downloaded Firebird Embedded server (Firebird Embedded Server v2.5.0).
Added a reference to FirebirdSql.Data.FirebirdClient.dll to my project.
Extracted and Copied fbembed.dll file to my application's directory.
Added my FDB file "TEST.FDB" to my application's directory.
Added "using FirebirdSql.Data.FirebirdClient;" statement.
So far so good (I suppose)...
Now when I try to connect to my FDB file using the following code:
FbConnection con = new FbConnection("User=SYSDBA;" + "Password=masterkey;" + "Database=TEST.FDB;" + "DataSource=127.0.0.1;" + "Port=3050;" + "Dialect=3;" + "Charset=UTF8;");
try {
con.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
I always get the messagebox which means the code is not connecting to my DB file properly.
am I doing something wrong? I'm really still noob with C# and I have no idea how to do this or fix it and I hope someone will help me with this.
thanks :)
EDIT: here is what I get in the exception:
FirebirdSql.Data.FirebirdClient.FbException
(0x80004005): Unable to complete
network request to host "127.0.0.1".
---> Unable to complete network request to host "127.0.0.1". at
FirebirdSql.Data.FirebirdClient.FbConnectionInternal.Connect()
at
FirebirdSql.Data.FirebirdClient.FbConnectionPool.Create()
at
FirebirdSql.Data.FirebirdClient.FbConnectionPool.CheckOut()
at
FirebirdSql.Data.FirebirdClient.FbConnection.Open()
at
fbTestApp.Form1.button1_Click(Object
sender, EventArgs e) in C:\Documents
and Settings\ermac\My Documents\Visual
Studio
2010\Projects\fbTestApp\fbTestApp\Form1.cs:line
25
I finally I found the solution after 6 hours of work :)
most of answers on google are either wrong or so old.
all of them say that I only need to include fbembed.dll file to my project..
after some investigations I made. I found that I also need to add firebird.msg, firebird.conf, icudt30.dll, icuin30.dll, icuuc30.dll and ib_util.dll to my project files and to the output folder..
important notice: never use compact .Net data provider. because they made it for Normal and super firebird servers only. it won't work with embedded servers.
With Firebird 2.5 embedded, I copy all this files to the application directory :
aliases.conf (optional)
fbembed.dll
firebird.conf
firebird.msg
ib_util.dll
icudt30.dll
icuin30.dll
icuuc30.dll
Microsoft.VC80.CRT.manifest : -- Not sure if this 3 files are necessary
msvcp80.dll : -- but i copy them :)
msvcr80.dll : -- see http://www.firebirdnews.org/?p=2248
intl\fbintl.conf : Without those files you can't use
intl\fbintl.dll : all charset and collations
udf\* : if you want to use pre-build UDF
In the connection string, I specify that the server is embedded wih serverType=1:
User=SYSDBA;Password=masterkey;Database=E:\TEST.FDB;Dialect=3;Charset=UTF8;ServerType=1;
I forgot also IDPLicense.txt and IPLicense.txt, I think we have to also distribute them with the application for license issue ?
I put the Firebird DLLs in a dir in the project called Firebird. Added a Post Build event to copy the files.
copy $(ProjectDir)Firebird\*.dll $(ProjectDir)$(OutDir)*.dll"
These are the files and distribution you need for Firebird 3.0.5:
- root\plugins\engine12.dll
- root\intl\fbintl.conf
- root\intl\fbintl.dll
- root\fbclient.dll
- root\icudt52.dll
- root\icudt52l.dat
- root\icuuc52.dll
I check them out at the beginning of my application so I can inform what can go wrong.

Categories