C# can't get datas from stored procedure with opendatasource and Microsoft.ACE.OLEDB.16.0 - c#

I have a strange issues reading data from an Eexcel file.
I made a query in SQL Server with OPENDATASOURCE:
SELECT COMPETENZA, [CODICE CLEINTE], [RAGIONE SOCIALE], MODELLO, VARIANTE,
TIPOLOGIA, ESSENZA, FINITURA, TAPPEZZERIA, COMMESSA, ROUND([% MOL SU RICAVI NETTI] * 100,2) as MARGINE
FROM OPENDATASOURCE('Microsoft.ACE.OLEDB.16.0',
'Data Source=K:\UTENTI\SAMUELE\temp id commesse\ID Commesse produzione.xls;Extended Properties=EXCEL 12.0')...['Consuntivi produzione$']
WHERE MODELLO IS NOT NULL AND [% MOL SU RICAVI NETTI] IS NOT NULL
If I execute this query in a stored procedure, it works fine.
But when I execute from C# by an HttpGet I get this issues:
System.Data.SqlClient.SqlException (0x80131904): Cannot initialize the data source object of OLE DB provider "Microsoft.ACE.OLEDB.16.0" for linked server "(null)".
This is my C# code:
[HttpGet]
public async Task<JsonResult> GetMarginiCommessaListJSON()
{
var yourdata = GetMarginiCommessaList();
return Json(new { data = yourdata });
}
public List<MarginiCommessa> GetMarginiCommessaList()
{
SqlDataReader reader;
SqlConnection sqlConn = new SqlConnection(_configuration["dbConnectionString"]);
string sqlCmdStr = "MARGINI_COMMESSE";
SqlCommand sqlCmd = new SqlCommand(sqlCmdStr, sqlConn);
sqlCmd.CommandType = CommandType.StoredProcedure;
List<MarginiCommessa> allestList = new List<MarginiCommessa>();
try
{
using (sqlConn)
{
sqlConn.Open();
reader = sqlCmd.ExecuteReader();
while (reader.Read())
{
allestList.Add(new MarginiCommessa
{
anno = reader.GetValue(0).ToString(),
codCli = reader.GetValue(1).ToString(),
nomCli = reader.GetValue(2).ToString(),
modello = reader.GetValue(3).ToString(),
variante = reader.GetValue(4).ToString(),
tipologia = reader.GetValue(5).ToString(),
essenza = reader.GetValue(6).ToString(),
finitura = reader.GetValue(7).ToString(),
tapezzeria = reader.GetValue(8).ToString(),
commessa_qta = reader.GetValue(9).ToString(),
margine = reader.GetValue(10).ToString()
});
}
reader.Close();
sqlConn.Close();
}
}
catch (Exception e)
{
System.IO.File.WriteAllText(GlobalVariables.errorFolderLocation + "GetMarginiCommessaListJSON.txt", e.ToString());
}
return allestList;
}
And this is my Stored procedure:
ALTER PROCEDURE [dbo].[MARGINI_COMMESSE]
AS
BEGIN
SET NOCOUNT ON;
SELECT COMPETENZA, [CODICE CLEINTE], [RAGIONE SOCIALE], MODELLO, VARIANTE,
TIPOLOGIA, ESSENZA, FINITURA, TAPPEZZERIA, COMMESSA, ROUND([% MOL SU RICAVI NETTI] * 100,2) as MARGINE
FROM OPENDATASOURCE('Microsoft.ACE.OLEDB.16.0',
'Data Source=K:\UTENTI\SAMUELE\temp id commesse/ID Commesse produzione.xls;Extended Properties=EXCEL 12.0')...['Consuntivi produzione$']
WHERE MODELLO IS NOT NULL AND [% MOL SU RICAVI NETTI] IS NOT NULL
END
I really don't understand why in SQL Server it works fine and in C# not.
How can I fix this?

OP #1:
I have a strange issues reading datas from an excel file. I made a query in mssql with OPENDATASOURCE: If i execute this query in a stored procedure, it works fine.
OP #2:
But when i execute from c# by an HttpGet i get this issues:
Firstly, that's an apples and oranges comparison. On one hand you are using MySQL and the other SQL Server. The latter case you also have a web app using ADO.NET in order to reach the stored proc.
Now I can't vouch for MySQL or whatever OPENDATASOURCE is doing in both occasions but one thing is certain - you appear to be using ACE OLEDB "Jet" in a server setting which may be the cause of your issues. Crashes aside, using ACE might have licensing issues. See below.
Microsoft (my emphasis):
Although such programmatic development can be implemented on a client system with relative ease, a number of complications can occur if Automation takes place from server-side code such as Microsoft Active Server Pages (ASP), ASP.NET, DCOM, or a Windows NT service.
NOTE: In this context, the Access Database Engine Redistributable and Access Runtime are considered Microsoft Office components.
...and:
Developers who try to use Office in a server-side solution need to be aware of five major areas in which Office behaves differently than anticipated because of the environment.
...and most importantly (my emphasis):
Besides the technical problems, you must also consider licensing issues. Current licensing guidelines prevent Office applications from being used on a server to service client requests, unless those clients themselves have licensed copies of Office. Using server-side Automation to provide Office functionality to unlicensed workstations is not covered by the End User License Agreement (EULA).
Conclusion
So even if you fix the technical issue, be mindful of that last pointer.
See also
Considerations for server-side Automation of Office, Microsoft

Related

asp.net c# code works (from VS2022 and on IIS10) on local machine to connect to SQL Server DB it does not work on Webserver

I don't get it why my (very simple) code is working properly on my local machine from Visual Studio 2022 and on the local IIS 10 to connect to a sql server express (15) and on my webserver it's not. I'm sure that's a really simple quesion for you.
What I'm tryin' to do is a simple login page. My code in the Login.aspx is:
using System.Data;
using System.Data.SqlClient;
try
{
SqlConnection con = new SqlConnection(#"Data Source=BERLIN\SQLEXPRESS;Initial Catalog=membersarea; User ID=sa;Password=Test2022!");
SqlCommand sqlCmd = new SqlCommand("select * from useraccount where username=#userName and passWord=#Password", con);
sqlCmd.Parameters.AddWithValue("#userName", tbxUsername.Text.ToString());
sqlCmd.Parameters.AddWithValue("#passWord", tbxPassword.Text.ToString());
SqlDataAdapter sqlAdapter = new SqlDataAdapter(sqlCmd);
DataTable datatable = new DataTable();
sqlAdapter.Fill(datatable);
con.Open();
int i = sqlCmd.ExecuteNonQuery();
con.Close();
if (datatable.Rows.Count > 0)
{
Session["userName"] = tbxUsername.Text.ToString();
datatable.Dispose();
Response.Redirect("Content.aspx");
}
else
{
lblMessage.Text = "Benutzername oder Passwort falsch.";
lblMessage.ForeColor = System.Drawing.Color.DarkOrange;
lblMessage.Visible = true;
}
}
catch(Exception ex)
{
}
(I know that I'm not supposed to do this with the sa account, just to keep it simple... The only thing I do on the web server is to change the name of the sql server instance. Management Studio works fine with this User Id and Password on my web server. I installed the sql server using Plesk and I don't think it is working properly within plesk. Using the Management Studio I can restore backups, queries, create new accounts, etc.)
My Content.asps says Hi (including my name) and shows the Logout-Button. If you enter credentials that are not correct it says so and if you try to go to the content-Page without loggin' in you're redirected to the Login-page. That is what I want. Trouble is, it's not workin' on my webserver. It is simply doin' nothing. No error message, or something else. It takes a while, password is cleared again and username is still there. (Doesn't matter which credentials are used.)
I don't think that it comes to the first line of my code, and I don't know why. Are there DLLs that are needed, or what else did I forget? I'm pretty sure this is a absolute beginner problem but I can't figure it out.
Tried to fill in some code to alter the lblMessage, to find out where the problem starts, but nothing of it is displayed.
I think the trouble started when I checked the pattern web forms while creating the project. In the bin folder there is a "name-of-my-project".dll and a "name-of-my-project".pdb file. Those two are generated if you recreate your project. I'm pretty sure you guys know that - I did not. Or better I do know that they were generated, but not that they are necessary. (As I wrote before, I'm at the very beginning.)
In guess that in this *.pdb and/or *.dll the connection string is stored, too. When I recreate my project with the valid connection string for the web server and upload them, too - everything works as expected. Thank you, guys for your ideas.

.NET Dapper/MySql 8.0 issue: Only root user is able to execute stored procedure. Other users get SqlNullValueException [duplicate]

I am trying to setup my .NET 4.7.1 program that is connecting to a MySQL database 8.0 to use the minimum privileges to run.
The .NET program is using MySql.Data to make connection. The minimum right for a user to execute a stored procedure is typically only EXECUTE privilege. This works fine from MySQL workbench or command line.
Upon running the .NET program this does return the following exception:
System.Data.SqlTypes.SqlNullValueException: 'Data is Null. This method or property cannot be called on Null values.'
To make it easy, I have create a very small demo program to demonstrate the issue.
Setup of the database:
CREATE DATABASE Spike;
CREATE PROCEDURE TestAccess()
BEGIN
END;
CREATE USER Spike#localhost IDENTIFIED WITH mysql_native_password BY 'sample';
GRANT EXECUTE ON PROCEDURE `TestAccess` TO Spike#localhost;
Setup program code:
static void Main(string[] args)
{
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample"))
{
conn.Open();
Console.WriteLine("Connection open");
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
cmd.CommandText = "TestAccess";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
Console.WriteLine("Query executed");
}
Console.ReadKey();
}
The crash happens at the line cmd.ExecuteNonQuery();
The stack from the crash is interesting, since it seems to indicate that the information_schema is queried. When logging all statements I can see that the last statement before the exception is:
SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess'
I cannot grant different rights on information_schema, but I could give more rights on the stored procedure to make more information visible in the routines table, this feels wrong however. Simple tests with granting CREATE and ALTER access also did not work.
Is there something else I can do, without granting too much privileges?
This appears to be a bug in Connector/NET, similar to bug 75301 but a little different. When it's trying to determine parameter metadata for the procedure, it first creates a MySqlSchemaCollection named Procedures with all metadata about the procedure. (This is the SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess' query you see in your log.)
The Spike user account doesn't have permission to read the ROUTINE_DEFINITION column, so it is NULL. Connector/NET expects this field to be non-NULL and throws a SqlNullValueException exception trying to read it.
There are two workarounds:
1) The first, which you've discovered, is to set CheckParameters=False in your connection string. This will disable retrieval of stored procedure metadata (avoiding the crash), but may lead to harder-to-debug problems calling other stored procedures if you don't get the order and type of parameters exactly right. (Connector/NET can no longer map them for you using the metadata.)
2) Switch to a different ADO.NET MySQL library that doesn't have this bug: MySqlConnector on NuGet. It's highly compatible with Connector/NET, performs faster, and fixes a lot of known issues.
I found an answer with which I am quite pleased. It is changing the connection string by adding CheckParameters=false:
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample;CheckParameters=false"))
This disables parameter checking, and thereby information_schema queries.

SQL Slow in code not SSMS

I am running into issues working with a very large table from C# .Net 4.0.
For reference the table has ~120 Million rows.
I can't do even a simple query like
SELECT TOP(50) *
FROM TableName
WHERE CreatedOn < '2015-06-01';
From code it will timeout (Default setting - 15 seconds I believe), but in SSMS it is instant.
There is an index on the column in the WHERE clause. I have also tried explicitly casting the string to a DateTime, and using a DateTime parameter instead of a literal value.
I tried a different query that filters by the PK (bigint, identity, clustered index) If I do something like "Where TableRowID = 1" it works fine from code, but if I try to use "<" or "<=" instead it will timeout (returns instantly in SSMS), regardless of how many rows are turned.
The execution plans are very simple and are exactly the same.
I have tried changing ARITHABORT but that has had no effect.
I tried having the Application connect with my own account (SSPI) instead of its own credentials with no effect.
I have been researching this issue for a few days, but everything I have found blames different execution plans.
Does anyone have any idea what could be causing this issue?
The .Net code looks like this:
private DataSet ExecuteQuery(string query, string db, List<SqlParameter> parms = null)
{
string connectionString = ConfigurationManager.ConnectionStrings[db].ToString();
SqlConnection con = new SqlConnection(connectionString.Trim());
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter();
try
{
con.Open();
DataSet ds = new DataSet();
sqlDataAdapter.SelectCommand = new SqlCommand(query, con);
sqlDataAdapter.SelectCommand.CommandType = CommandType.Text;
if (parms != null)
{
foreach (SqlParameter p in parms)
{
sqlDataAdapter.SelectCommand.Parameters.Add(p);
}
}
sqlDataAdapter.Fill(ds);
if (ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
{
return ds;
}
return null;
}
finally
{
if (sqlDataAdapter != null)
sqlDataAdapter.Dispose();
if (con != null)
con.Dispose();
}
}
The error message I get in .Net is the standard timeout message:
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
Here are my experience when dealing the issues.
Very C# sql code passed to sql server is
SELECT TOP(50) *
FROM TableName
WHERE CreatedOn < '2015-06-01'
Make sure the criteria. If it takes "instant time" to retrieve records on SSMS, the sql statement and db optimization is ok.
As other people have pointed out, you should post your C# codes and see what happens. There could be other issues. Could that be network? Could that be web.config? Do you call directly from C# code? Do you call via web service?
when you said time out? Does it time out at the time you execute the query. There is very little information you provide. Do you use third party routines (such as written by vendor or your company) to execute queries? If it possible, put the break point at the code that execute sql statement. What I mean is dig all the way to native codes, and put the break codes.
120 million records. Looks like the database has be optimized if it runs very fast on SSMS. I would take look outside SQL server.
good luck
My first step there would be to look at what your code is sending to the sql server. I'd begin by running the sql profiler. if you're not familiar with it. Here is a link on how to use it.
https://www.mssqltips.com/sqlservertip/2040/use-sql-server-profiler-to-trace-database-calls-from-third-party-applications/
After this you may want to look into network traffic times between the 2 servers.
Then look at IIS and see how it's setup. Could be a setting is wrong.
Check the error logs and see if you have any errors as well.
When you execute code in SSMS, the system is setting some default values on your connection. Specifically, look at Tools --> Options --> Query Execution --> Sql Server --> Advanced (and also ANSI). These statements are executed on your behalf when you open a new query window.
When you create your connection object in C#, are you setting these same options? If you don't explicitly set them here, you are taking the default values as defined in the actual SQL Server instance. In SSMS, you can get this by viewing the properties of the server instance and choosing the Connections page. This shows the default connection options.
You can also get this information without using the UI (you can do this in a separate application that uses the same connection string, for example). This article on MSSQLTips should guide you in the right direction.

.NET ODAC query returning no results, but SQL DEVELOPER returns results

When I execute a simple select query in SQL Developer against a newly added table or an older table with newly added data, I receive results. But if I run the exact same query in .NET/C# using the most recent Oracle Data Access Client under .NET 4.0, I receive zero results.
I have verified the connection string is correct, and that I am connecting to the same DB, and I have tested using simple "select * from table" queries. Using the same exact .NET code querying against older data...it works just fine. I can only conclude that this is a bug of some sort, or maybe someone who is an Oracle expert knows how this can occur. I know DBs are complex machines and therefore I am hoping there is some logical explanation as to how this can occur...and how I can fix it.
I am an Oracle newbie, but I am a veteran programmer and problem solver. This one really has me stumped.
This is my first SO question, so please be gentle...thanks!
Here is my sample code that returns error saying "...table does not exist...". But table DOES exist and the query works fine in SQL DEV.
String prod_connstr = "Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST = 10.0.0.17) (PORT = 2621)) " +
"(CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XXXXX)));User Id=XXXXX;Password=XXXXX";
String sqlStr = "select * from z_test";
OracleConnection conn = new OracleConnection(prod_connstr);
try
{
conn.Open();
OracleCommand cmd = new OracleCommand(sqlStr, conn);
OracleDataReader dr = cmd.ExecuteReader();
MessageBox.Show(dr.HasRows.ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error");
}
finally
{
conn.Dispose();
}
Every time I have seen "...table does not exist..." where you know it does, it means the user you are connecting as (in the connection string) does not have select granted to it. Now if you are connecting with SQL developer and you connection string with the same schema, you have me stumped.
edit: as Oğuz Sezer pointed out if your db doesn't have public synonyms for the tables you will need to use Schema.table (forgot about that)

Retrieve custom table data with Azure SQL

I have an Azure Web Site, using a free Azure SQL database, and I have installed Umbraco CMS 7.1.1 to develop the site with. I have also created a custom table using Azure's SQL Management feature and I have created a couple of test rows with dummy text. How can I connect to my custom table and display the data on a page?
Usually I work with MySQL and fetching data is relatively easy to do but I'm having trouble converting my code to work with Azure SQL. The following is my code which is almost identical to when I use MySQL, but with this snippet I get the error "Keyword not supported: 'flush interval'". Has anyone been able to fetch custom table data with Azure SQL?
ConnectionStringSettings cs = ConfigurationManager.ConnectionStrings["umbracoDbDSN"];
using(SqlConnection con = new SqlConnection(cs.ToString()))
{
string sql = "SELECT * FROM [dbo].[MyTable]";
con.Open();
using(SqlCommand cmd = new SqlCommand(sql,con))
{
SqlDataReader reader = cmd.ExecuteReader();
}
con.Close();
}
If you are accessing this in an Umbraco-based website and have the tables within the same database that Umbraco is using, you can get the connection string by accessing the ConnectionString property on the DatabaseContext:
using (var con = new SqlConnection(Umbraco.Core.ApplicationContext.Current.DatabaseContext.ConnectionString)) {
// Your code here
}
However, you may find it advantageous to use the built-in PetaPoco support that Umbraco offers. There's a good example of using PetaPoco here: http://creativewebspecialist.co.uk/2013/07/16/umbraco-petapoco-to-store-blog-comments/

Categories

Resources