Using application roles with DataReader - sql-server

I have an application that should use an application role from the database.
I'm trying to make this work with queries that are actually run using Subsonic (2).
To do this, I created my own DataProvider, which inherits from Subsonic's SqlDataProvider.
It overrides the CreateConnection function, and calls sp_appsetrole to set the application role after the connection is created.
This part works fine, and I'm able to get data using the application role.
The problem comes when I try to unset the application role. I couldn't find any place in the code where my provider is called after the query is done, so I tried to add my own, by changing SubSonic code. The problem is that Subsonic uses a data reader. It loads data from the data reader, and then closes it.
If I unset the application role before the data reader is closed, I get an error saying: There is already an open DataReader associated with this Command which must be closed first.
If I unset the application role after the data reader is closed, I get an error saying ExecuteNonQuery requires an open and available Connection. The connection's current state is closed.
I can't seem to find a way to close the data reader without closing the connection.

Do you have to use the role for every query?
If not you can use a SharedDbConnectionScope()
using(var scope = new SharedDbConnectionScope())
{
// within this using block you have a single connection
// that isn't closed until scope.Dispose() is called
// (happens automatically while leaving this block)
// and you have access to scope.CurrentConnection
// Do your init stuff
SetRole(scope.CurrentConnection);
var product = new Product();
product.Code = "12345";
product.Save();
// Revert to normal
UnsetRole(scope.CurrentConnection);
}

The problem is that Subsonic executes its reader with CloseConnection.
If I make it not close the connection I can unset the application role after the reader is closed.

May be you can subscribe to the event like this:
Connection.StateChange += new System.Data.StateChangeEventHandler(Connection_StateChange);
And then do some actions according to the new state of this connection:
if(e.CurrentState== System.Data.ConnectionState.Open)
dbworker.ExecuteCommand("EXEC sp_setapprole application, 'password'");

Related

How does Dapper execute query without explicitly opening connection?

We are using Dapper for some data access activity and are using the standard recommended approach for connecting to database as follows:
public static Func<DbConnection> ConnectionFactory = () => new SqlConnection(ConnectionString);
However, if we try and execute a statement, in the docs it show that you need to first state:
using (var conn = ConnectionFactory())
{
conn.Open();
var result = await conn.ExecuteAsync(sql, p, commandType: CommandType.StoredProcedure);
return result;
}
That means, you have to explicitly open the connection. However, if we leave out the statement conn.open(), it also works and we are worried if in such cases the connection may not be disposed of properly.
I would appreciate any comments as to how the SQL gets executed without explicitly opening any connection.
Dapper provide two ways to handle connection.
First is - Allow Dapper to handle it.
Here, you do not need to open the connection before sending it to Dapper. If input connection is not in Open state, Dapper will open it - Dapper will do the actions - Dapper will close the connection.
This will just close the connection. Open/Close is different than Dispose. So, if you really want to Dispose the connection better switch to second way.
Second is - Handle all yourself.
Here, you should explicitly create, open, close and dispose the connection yourself.
Please refer to following links for more details:
https://stackoverflow.com/a/51138718/5779732
https://stackoverflow.com/a/41054369/5779732
https://stackoverflow.com/a/40827671/5779732

IFSFile when user PASSWORD *NONE

I am facing some troubles while trying to create an IFSFile using IFSFile object from JT400.jar. The problem that I am facing is when the process that calls the JAVA is called by a BATCH user(without login enabled into AS400 machine).
Exception given
Password is *NONE.:XXXXXX com.ibm.as400.access.AS400SecurityException: Password is *NONE.:XXXXXX
at com.ibm.as400.access.AS400ImplRemote.returnSecurityException(AS400ImplRemote.java:2219)
at com.ibm.as400.access.CurrentUser.getUserInfo(CurrentUser.java:79)
at com.ibm.as400.access.AS400ImplRemote.getPassword(AS400ImplRemote.java:1411)
at com.ibm.as400.access.AS400ImplRemote.signon(AS400ImplRemote.java:2507)
at com.ibm.as400.access.AS400.sendSignonRequest(AS400.java:3351)
at com.ibm.as400.access.AS400.promptSignon(AS400.java:2938)
at com.ibm.as400.access.AS400.signon(AS400.java:4246)
at com.ibm.as400.access.AS400.connectService(AS400.java:1336)
at com.ibm.as400.access.IFSFile.chooseImpl(IFSFile.java:630)
at com.ibm.as400.access.IFSFile.copyTo(IFSFile.java:729)
at com.ibm.as400.access.IFSFile.copyTo(IFSFile.java:699)
Code used:
AS400 as400 = new AS400("localhost");
//Obtain the template path
String templatePath ="/HOME/XXX/auth.txt";
IFSFile templateAuth = new IFSFile(as400,templatePath);
templateAuth.copyTo(fileXML + ".xml");
I have check some opened threads but no results obtained. (find below the threads commented)
JT400 Read File From IFS with user without password
Java IFSFile on Iseries testing over PC
There is any option to generate an IFSFile when the process is called by a BATCH user(note that when the process is called by a user with login enabled, the process is working as expected)
I need something similar to what is done when a JDBCAppender is created, JDBCAppender object allows setUser(null) and setPassword(null) to enable batch users to write into a table.
Thanks all!
I have recently had a similar problem when trying to use CommandCall whilst running under a profile with PASSWORD is *NONE. I (eventually) solved it by using the native Java toolbox at /QIBM/ProdData/Java400/jt400ntv.jar (which happens to be a symbolic link). I didn't have to make any code changes:
AS400 as400 = new AS400();
CommandCall cc = new CommandCall(as400);
String wrkenvvar_cmd = MessageFormat.format("ADDENVVAR ENVVAR('JAVA_HOME') VALUE(''{0}'') REPLACE(*YES)",path);
boolean ok = cc.run(wrkenvvar_cmd);
I hope that helps.

Should a InitialDirContext object be closed explicitly everytime?

There is an application that talks to LDAP on a need basis for several operations like user info fetch, list of users, list of groups, email ids etc. Every time a request has to be made an InitialDirContext object is created and used as follows.
Properties ldapProperties = new Properties();
ldapProperties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
ldapProperties.put(Context.PROVIDER_URL, "ldaps://serv:636");
ldapProperties.put(Context.SECURITY_AUTHENTICATION, "simple");
ldapProperties.put(Context.SECURITY_PRINCIPAL, "user");
ldapProperties.put(Context.SECURITY_CREDENTIALS, "password");
ldapProperties.put("java.naming.ldap.attributes.binary", "tokenGroups");
InitialDirContext ctx = new InitialDirContext(ldapProperties);
ctx.search(....);
Should this "ctx" object be closed using the close() method?
If its not closed and there are multiple new InitialDirContext() creations will the old ones be automatically closed?
If it was just an internal object it will be garbage collected but what about this connection object?
No reason to close the context object each time.
You should be aware that it would be possible that the server (or some network device like a Load balancer proxy) would close the connection and then you may need to reinitialize the connection.
We have some Example JNDI solutions you may find helpful.
-jim

Avoiding the window (WPF) to freeze while using TPL

I am building a WPF which has a button that execute a sql query in sql server (the query could take a long time to run).
I want to use TPL for doing that.
This code:
var result = Task.Factory.StartNew(() => { command.ExecuteNonQuery(); });
gives this exception:
ExecuteNonQuery requires an open and available Connection. The connection's current state is closed.
I guess this is due to the fact that the query runs on a different thread and is not aware of the open connection.
I have 2 questions:
1. How do I make the new thread know of this open connection?
2. After solving this ,How do I get the window not to freeze due to this query.
Thanks
You will have to create and open the connection for this command within the Task's body. Either that or don't close the connection outside the Task, which I assume is what you're doing here, but can't tell from the one line of code you pasted.
I would personally do it all inside the Task body. Why should the user have to wait for you to even get the connection/command setup if they don't have to? Also there's the chance that you connection is a shared instance and that won't work across threads.
Once you get the DB work into a Task it will be executed on a Thread Pool thread by default which will free up the WPF dispatcher thread to go back to processing UI events preventing the "freezing". Most likely you will want to update the UI after that DB task has completed and to do that you would hpjust add a continuation task, but in order to be able to manipulate the UI from that continuation task you need to make sure it's explicitly scheduled to run on the Dispatcher thread. This is done by explicitly specifying a TaskScheduler for the current synchronization context while scheduling the continuation. That would look something like this:
Task backgroundDBTask = Task.Factory.StartNew(() =>
{
... DB work here ...
});
backgroundDBTask.ContinueWith((t) =>
{
... UI update work here ...
},
TaskScheduler.FromCurrentSynchronizationContext());
The magic here is the use of the TaskScheduler::FromCurrentSynchronizationContext method which will schedule the continuation to be executed on the Dispatcher thread of the current call.
In addition to #Drew Marsh answer,
To avoid Exception:
The current SynchronizationContext may not be used as a TaskScheduler
You can use check for Synchronization Content Exists:
private static TaskScheduler GetSyncronizationContent() =>
SynchronizationContext.Current != null ?
TaskScheduler.FromCurrentSynchronizationContext() :
TaskScheduler.Current;
And use it instead:
Task backgroundDBTask = Task.Factory.StartNew(() =>
{
//... DB work here ...
});
backgroundDBTask.ContinueWith((t) =>
{
//... UI update work here ...
},
GetSyncronizationContent());

SQL Server Asynchronous Execute?

I am looking for a way to let my C# (4.0) app send data to a SQL Server 2008 instance, asynchronously. I kind of like what I saw at http://nayyeri.net/asynchronous-command-execution-in-net-2-0 but that is not quite what I am looking for.
I have code like this:
// myDataTable is a .NET DataTable object
SqlCommand sc= new SqlCommand("dbo.ExtBegin", conn);
SqlParameter param1 = sc.Parameters.AddWithValue("#param1", "a");
SqlParameter param2 = sc.Parameters.AddWithValue("#param2", "b");
SqlParameter param3 = sc.Parameters.AddWithValue("#param3", myDataTable);
param3.SqlDbType = SqlDbType.Structured;
param3.TypeName = "dbo.MyTableType";
int execState = sc.ExecuteNonQuery();
And because the myDataTable is potentially large, I don't want the console app to hang while it sends the data to the server, if there are 6 big loads I want them all going at the same time without blocking at the console app. I don't want to send serially.
All ideas appreciated, thanks!
set the AsynchronousProcessing property on the connection string to True.
Use BeginExecuteNonQuery
But what is dbo.ExtBegin doing? It all depends on it, as the calls may well serialize on locks in the database (at best) or, at worst, you may get incorrect results if the procedure is not properly designed for concurency.
Create a thread and execute the query within that thread, make sure not to have subsequent database calls that would cause race conditions.
My first thought would be to spawn a new thread for the inserts, and have the main thread check the spawned thread's execution with AutoResetEvent, TimerCallback, and Timer objects.
I do it in Silverlight all the time.
Take a look at using Service Broker Activation. This will allow you to call a stored proc and have it run on it's own thread why you continue on the current thread.
Here is an excellent article that goes over how to do this.

Resources