This is kind of a 'double' question that might have a single answer.
I'm working with an Odbc Connection with an AS/400, with my connection string as follows:
driver={iSeries Access ODBC Driver}; system={0}; uid={1}; pwd={2}; DefaultLibraries=*USRLIBL;
I'm able to connect to the system fine.
*USRLIBL contains all the necessary libraries from the user (which is of the type 'API only' which has access to all user libraries).
However, when I try to access certain ERP libraries, it says they can't be found, while other ones can.
So as an extremely basic walkthrough:
1. Open Connection - Query File 1 from Library A: OK! - Close Connection
2. Open Connection - Query File 2 from Library A: OK! - Close Connection
3. Open Connection - Query File 1 from Library B: Exception SQL0204 - in UserName type *FILE not found
Ok, so I added in the specific library that the ERP files would be in, making the connection string as follows, just to test the program:
driver={iSeries Access ODBC Driver}; system={0}; uid={1}; pwd={2}; DefaultLibraries=*USRLIBL, LibraryB;
But then I start getting a different problem (another extremely basic walkthrough)
1. Open Connection - Query File 1 from Library A: OK! - Close Connection
2. Open Connection - Query File 2 from Library A: OK! - Close Connection
3. Open Connection - Query File 1 from Library B: OK! - Close Connection
4. Open Connection - Query File 1 from Library A again: Exception SQL0202 - in LibraryB type *FILE not found.
So my question(s) are:
Why doesn't the odbc connectionstring DefaultLibraries=*USRLIBL not return the correct libraries? (Note: I also tested this using an iDB2Connection which in fact works fine... however, the iDB2Connection can not be deployed as it literally crashes the server)
Why does the second walkthrough throw an exception, it just seems to 'skip past' *USRLIBL after reading from LibraryB even once.
Any thoughts?
Begin Edit:
There are actually two users, DEV and PROD
The *USRLIBL gets all the necessary Libraries from the Environment itself, so if when opening the connection, it detects a localhost environment, or anything that's unsecure (plus a few other caveats), it defaults to DEV log in credentials before creating the connection. This is why the system, uid, and pwd are designated as parameters in the connection (and not just stackoverflow I-dont-want-to-give-out-data placeholders)
The *USRLIBL then pulls the necessary libraries from the API user.
To Clarify, the way it's set up does work using the iDB2 Connector, but because of the limitations of our ERP system (we think), using it with an IIS 7 server causes a catastrophic failure, so we're working with the ODBC connector.
End Edit:
You can qualify your table names as library.filename and not have to deal with any library list issues.
For more information:
Client Access ODBC: Default Libraries Setting
ODBC connection string keywords
Excerpts of the relevant parts are:
With SQL naming convention, the operating system does not perform a library list search to locate an unqualified object. If a default collection is defined, the default collection is used to resolve unqualified SQL statements.
...
With the SYS naming convention, the unqualified SQL statements go to the default collection. If there is no default collection, the current library is used. If no current library is specified, the library list is used.
...
Default Collection
A job attribute set by ODBC that determines the library used when processing SQL statements that contain unqualified SQL names. When a default collection is set all unqualified objects except procedures, functions and types must reside in the default collection, regardless of naming convention.
...
How can I get ODBC to search the library list?
As explained above, edit the ODBC data source and set system naming to SYS. The default library must be empty, or on versions older than R510, the default libraries setting must start with a comma so that no default collection is defined (for example, ",MYLIB1, MYLIB2").
Try this connection string to enable system naming and to not set a default library:
driver={iSeries Access ODBC Driver}; system={0}; uid={1}; pwd={2}; naming=1; DefaultLibraries=,*USRLIBL,LibraryB;
If anyone runs into this post and is using the IBM.Data.DB2.iSeries .NET data provider as I am, the key point taken from above was using the naming=1 and not specifying a "Default Collection". I was finally successful when using the following portion in my connection string
LibraryList= MyLibrary1,MyLibrary2,MyLibrary3,MyLibrary4;naming=1;
An alternative is to set up a separate user profile for each environment. Since the *USRLIBL is set by the job description, this would entail setting up a separate job description as well. For example:
user: WEB job desc: WEB library list: CUSTPROD, ITEMPROD, UTILITY
user: WEBTEST job desc: WEBTEST library list: CUSTTEST, ITEMTEST, UTILITY
The C# code does not change except for using the test or production user ID to authenticate.
Related
I use SQL Server CLR Integration to create an ASSEMBLY.
Load Command:
CREATE ASSEMBLY TcpClr FROM 'G:\TcpClrTest.dll' WITH PERMISSION_SET = UNSAFE
Without App.Config
The dll code contains :
string ip=ConfigurationManager.AppSettings["connection"].ToString();
Also the App.config contains :
<appSettings>
<add key="connection" value="127.0.0.1"/>
</appSettings>
But when I execute the PROCEDURE,the SQL Server shows an error System.NullReferenceException
Does SQL Server CLR Integration support App.config files?
You need to place a sqlservr.exe.config file in the \Binn folder of that instance's root folder. For example:
C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Binn
If you are using SQL Server 2008 R2 (SP1) or newer, you should be able to find the exact location via the following query, which shows the full path to sqlservr.exe:
SELECT [filename] FROM sys.dm_server_services WHERE servicename LIKE N'SQL Server (%';
In your code, you need this line at the top:
using System.Configuration;
And then this will work:
[SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
public static SqlString GetConfig(SqlString WhichOne)
{
ConfigurationManager.RefreshSection("connectionStrings");
return ConfigurationManager.ConnectionStrings[WhichOne.Value].ToString();
}
Contents of the sqlservr.exe.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="Stuff" connectionString="Trusted_Connection=true; Enlist=false;" />
<add name="ClrTest" connectionString="boo hoo" />
</connectionStrings>
</configuration>
It is important to note that, as stated in the "Using an Application Configuration..." link, changes made to the config file are not immediately available. HOWEVER, you do not need to force a reload by doing one of the methods mentioned in that article (i.e. DBCC FREESYSTEMCACHE, and restarting SQL Server). All that is required to get current information is to reload the particular section you are using via ConfigurationManager.RefreshSection(string sectionName) as shown in the example above. Please see note below regarding usage and performance.
Resources:
Using System.Configuration.dll in .NET sprocs and UDFs
Using an Application Configuration (app.config/web.config) File in SQL Server CLR Integration
Also, unless you absolutely need to, you shouldn't create your assembly as UNSAFE. If you are just trying to make TCP connections to other machines, that should only require EXTERNAL_ACCESS.
USAGE AND PERFORMANCE
As suggested by Joe B in a comment below, there is a slight performance hit for the RefreshSection operation. If the code containing the refresh is going to be called more than once every couple of minutes, then it can have a noticeable impact (an impact that is unnecessary given the lack of frequency of a config file changing). In this case, you will want to remove the call to RefreshSection from the code that is called frequently and handle the refresh independently.
One approach would be to have a SQLCLR Stored Procedure or Scalar Function that just does the refresh and nothing else. This can be executed whenever a change it made to the config file.
Another approach would be to unload the App Domain which will reload the config file upon the next time any SQLCLR object in that database is referenced. One fairly simple method to reload all App Domains in a particular Database (but not across the entire Instance) is to flip the TRUSTWORTHY setting On and then Off again, or Off and then On again, depending on the current state of that setting. The code below will check the current state of that setting and flip it accordingly:
IF (EXISTS(
SELECT sd.*
FROM sys.databases sd
WHERE sd.[name] = DB_NAME() -- or N'name'
AND sd.[is_trustworthy_on] = 0
))
BEGIN
PRINT 'Enabling then disabling TRUSTWORTHY...';
ALTER DATABASE CURRENT SET TRUSTWORTHY ON;
ALTER DATABASE CURRENT SET TRUSTWORTHY OFF;
END;
ELSE
BEGIN
PRINT 'Disabling then enabling TRUSTWORTHY...';
ALTER DATABASE CURRENT SET TRUSTWORTHY OFF;
ALTER DATABASE CURRENT SET TRUSTWORTHY ON;
END;
Please do not use any of the more drastic methods -- DBCC FREESYSTEMCACHE, disabling then enabling the clr enabled system setting, restarting the Instance, etc -- as it is almost never necessary to do so. Especially restarting the Instance, or DBCC FREESYSTEMCACHE which drops all cached data for the entire Instance, which affects much more than just SQLCLR.
UPDATE REGARDING SQL SERVER ON LINUX
SQL Server is now, starting with version 2017, available on Linux (woo hoo!). However, it seems that reading from the app config file does not work on Linux. I have tried many combinations of sqlservr.exe.[Cc]onfig and sqlservr.[Cc]onfig, etc, and the like and have not gotten anything to work. Specifying a config file can't work as that requires EXTERNAL_ACCESS permission and only SAFE Assemblies are allowed on Linux (as of right now, at least). If I find a way to get it working I will post the details here.
You'll obviously be getting a NullReferenceException because ConfigurationManager.AppSettings["connection"] is returning null and then you are calling ToString() on a null.
Until you posted your question the top ranking page for a Google search on CLR Integration app.config was this
Using an Application Configuration (app.config/web.config) File in SQL Server CLR Integration.
In the associated article by Jonathan Kehayias, he states
A common part of programming in .NET is to use an configuration file
to store configuration information in an easily modifiable location.
The app.config or web.config file is an invaluable inclusion in most
.NET projects and developers may need to maintain this functionality
as a part of logic sharing between objects in the database and the
application as well. The problem is that SQL CLR doesn't allow use of
the System.Configuration class in SQLCLR projects.
He then goes on to detail a workaround which involves editing the project file to inject a new key into an ItemGroup that links your app.config to the project. From there you can do some basica wrangling from within your code to create a UserDefinedFunction to return the connection string or appSetting you require.
You are best to read the article posted by him at the aforementioned Url as it's not my area and I would just end up blatantly plagiarizing his content to provide a step by step of how to do.
Are you trying to access the same SQL Server that the CLR is running on? If so, you can use a special type of connection string called a "context connection".
https://msdn.microsoft.com/en-us/library/ms131053.aspx
using(SqlConnection connection = new SqlConnection("context connection=true"))
{
connection.Open();
// Use the connection
}
Basically you tell the code that it should use the underlying SQL Server (in that context) and you won't even need to specify connection info. If you're trying to run arbitrary reusable code as a CLR, you're probably committing some sort of software crime and should just not do that.
This is how I did it. It's working perfectly for me, and I can install my assembly on any instance now and it will work perfectly.
SqlConnectionStringBuilder sqlb = new SqlConnectionStringBuilder("");
sqlb.ContextConnection = true;
string newConnStr = sqlb.ToString();
using (SqlConnection c = new SqlConnection(newConnStr))
{
c.Open();
//This is the database name
DatabaseName = c.Database;
//We need to use some simple SQL to get the server and instance name.
//Returned in the format of SERVERNAME\INSTANCENAME
SqlCommand cmd = new SqlCommand("SELECT ##SERVERNAME [Server]", c);
SqlDataReader rdr = cmd.ExecuteReader();
if (rdr.Read())
{
ServerName = rdr["Server"].ToString();
}
}
I'm trying to use Enterprise Library to create database connection and it gives the error "the requested database is not defined in configuration"
I have 2 config files. One is for appSettings and the other is for connection string. We use a custom framework to take the config values from an external path in the system, eg.
C:\application\environments\dev\environments.config
C:\application\environments\dev\connections.config
The environment.config has a connectionString element which has the configSource="connections.config".
When I run the application, I'm able to get all the appSetting from the environments.config, but when I try to call the DatabaseFactory.CreateDatabase("dbConnection"), it throws the error. I'm not sure if I'm missing something or not. I read through many articles and couldn't find the exact problem.
I use Enterprise Library Common and Data dll and their version is 3.1.1.0. My .NET framework is 4.0.
Can anybody please provide me some idea to make this work?
Do I need to make any setting changes in machine.config?
I have an old system which generated me a database in .CDB extension (i run on Firebird-1.5.6.5026-0-Win32) and i can access this database in IBExpert to query and stuff. But i need to write an application in .NET (VS 2010 4.0 framaework) so i can read this database and access some of the data to insert into a table inside SQLServer.
I tried many things, changed the server version and other things but i now all i get is ''Cannot find fbembed.dll'' exception error while trying to open the connection. My FB server doesnt have this file since he uses the 'fbclient.dll' already.
Any thoughts on how to connect my application to this .CDB database?
(this firebird version is the same that the legacy system is running, so i used the 1.7RC firebird .net provider within this server)
The connection string used is:
<add name="FirebirdConnectionString" connectionString="User=SYSDBA;Password=masterkey;
Database=localhost:C:\temp\BD\ECLECTIC.CDB;DataSource=localhost;Port=3051;
Dialect=3;Charset=NONE;Role=;Connection lifetime=15; Pooling=false;
MinPoolSize=0; MaxPoolSize=50; Packet Size=8192; ServerType=1;"
providerName="FirebirdSql.Data.FirebirdClient"/>
Unless you really want to use Firebird embedded (which you don't as you also specify localhost), you should not specify ServerType=1, but either leave it out entirely or set ServerType=0.
As to your other problem you mention in the comments, I suggest you check if this solves it and otherwise create a new question with more information.
I have C# application which uses SQL Server R2 as its database. That database is on a separate PC by the name of SERVER. SQL Server's instance name also server.
My windows application uses DataSet to communicate with the database. Now my SQL installed PC name is change to another name, ex SERVERHP. Now all my coding works want to change my connection string. Are there any other easy way to do it ?
I am to tried to edit hosts file, but it does not work for me.
This is my coding style (http://goo.gl/FQrkp). I am using DataSet with DataAdapter with IDE designers.
I have 100 ~ 150 forms. Now I cannot compile all codings. I want to easy method to connect that SQL Server database.
I want to have a way to hide the change of the hostname of the computer
You have a couple of options:
Globally replace all server names with IP address in connection strings in the app
Globally replace all server names with the new server name in the app
Add a CNAME record to the DNS table on the server (assuming of course you're in the same network, which you are if you're using computer names)
Add an entry to the LMHOSTS file (you can add as many names as you'd like that point to the same IP)
As I understand, it is SqlConnection used to connect to database, or something like that. Why don't you use SqlConnectionStringBuilder? Then you can dinamically construct connection string you need. Also, to get list of servers, you can use SqlDataSourceEnumerator, from namespace System.Data.Sql.
It sounds like you want to have a way to hide the change of the hostname of the computer (Server/Desktop/Virtualized instance of Windows, whatever) that is running your SQL Server.
This isn't my area of expertise, but I can't think of a way to do it that only involves your application code and just the computer.
If you control the local DNS you can create a CNAME entry with the old name that "points" at the new one. Depending on how your connection strings are stored, you might have to edit them or you might not. But you won't have to worry about the location of your SQL Server changing again because you can always edit your CNAME to point at the new location.
Note for the future - not your current problem: If you continue to use MS SQL Server in particular you'll want to be careful about moving it to a computer where it isn't the default instance because then you need to put the instance name in the connection string as well, which might force you to edit all of your application web.configs and app.configs again.
Are you using Visual Studio 2012 with your development efforts? I ran into a conflict with the mini SQL db VS installs (Using Premium version) and had to modify the ConnectionStrings section of my Machine.config file to point to my SQL database. For whatever reason, VS will write references to the mini db in the Machine.Config file (for whatever version of .Net you are leveraging) throwing potetial conflicts.
The file can be found in %systemroot%\Microsoft.Net\Framework64\dot net version\Config
If you're using an x86 processor the Framework64 folder is just called 'Framework'.
I am a beginner in working with databases. I am trying to access Oracle10g database from a c# application. But when I do so i get this error:
ORA-12154: TNS:could not resolve the connect identifier specified"
I'm using the following code:
string oradb = "Data Source=ORCL;User Id=system;Password=goodbye;";
OracleConnection conn = new OracleConnection(oradb); // C#
conn.Open();
Is there an error in the connection string oradb?
Start the Visual Studio, open View menu + Server Explorer.
Right mouse click on Data Connection + Add Connection + Select Oracle Database
server Name : localhost or name of your machine, set username & password and click on Test Connection to verify the above parameters. Press OK if test is succeeds.
From properties windows you can obtain connection String and it should be look a like:
Data Source=localhost;Persist Security Info=True;User ID=scott;Password=***********;Unicode=True
Oracle is just stating that it can't find the database.
If you're running a local Express Edition database, you should be able to just use XE as an instance name, and everything should already be set up, otherwise you can most easily add it to tnsnames.ora.
To find the correct tnsnames.ora to change, you can try (from the command prompt)
tnsping ORCL
That will tell you which files Oracle is using to try to find the database. If tnsping is an unknown command, you may have to search for it and go to the correct place before running it.
One you found the correct tnsnames.ora, you need to add the instance ORCL to it. There should be an existing file with examples, the syntax of that file is too complex to answer here, if you need help, Oracle has quite extensive documentation.
This is a very common oracle error. Simply put, it means that you have named the database you wish to be connected to and Oracle doesn’t know who the heck you’re talking about. I suggest 6 Steps to fix ORA-12154:
Check instance name has been entered correctly in tnsnames.ora.
There should be no control characters at the end of the instance or database name.
All paranthesis around the TNS entry should be properly terminated
Domain name entry in sqlnet.ora should not be conflicting with full database name.
If problem still persists, try to re-create TNS entry in tnsnames.ora.
At last you may add new entries using the SQL*Net Easy configuration utility.
More informations on oracle site or here : http://turfybot.free.fr/oracle/11g/errors/ORA-12154.html