ODP.net Connection Pooling: ClientID, Client Identifier never changes from first user who logs in

喜夏-厌秋 提交于 2019-12-04 19:24:30

Try using DBMS.Rest_Package before closing the connections.

The problem I think is with pooling turned on ODP is keeping the connection thus as each user opens and closes a connection with ODP, pooling is keeping the session package variables in memory; until the connection times out. However, since the time/out and re-establish of a connection from the database to the pool only occurs AFTER a connection is RETURNED to the pool, you're operating with someone else's session data.

This works fine both with pooling on and off. The ClientId and ClientInfo on the Oracle Session do not update until a command is executed.

Could you verify your if statement is correct? If _clientID <> "" Then _oracleConnection.ClientId = _clientID. Even when you close the connection, the clientId will still stay the same. Not sure where your setting/getting _clientId when you pass that into your method.

class Program
{
    static void Main(string[] args)
    {
        TestClientId test = new TestClientId();
        test.DoSomething("FirstClientId");
        test.DoSomething("ChangedClientId");
    }
}

public class TestClientId
{
    /// <summary>
    /// The connection string. 
    /// </summary>
    private const string ConnString = "DATA SOURCE=//server:port/service_name;USER ID=user;PASSWORD=pswd;";

    /// <summary>
    /// The oracle connection.
    /// </summary>
    private OracleConnection connection;

    /// <summary>
    /// The oracle session id.
    /// </summary>
    private long sid;

    /// <summary>
    /// Initializes a new instance of the <see cref="TestClientId"/> class.
    /// </summary>
    public TestClientId()
    {
        this.connection = new OracleConnection(ConnString);
    }

    /// <summary>
    /// Changes the client id of the oracle connection.
    /// </summary>
    /// <param name="clientId">The client id.</param>
    public void DoSomething(string clientId)
    {            
        this.connection.Open();
        this.sid = this.GetSessionId(this.connection);

        if (!string.IsNullOrEmpty(clientId))
        {
            this.connection.ClientInfo = clientId;
            this.connection.ClientId = clientId;                
        }

        OracleCommand command = new OracleCommand("select * from dual", this.connection);
        command.ExecuteNonQuery();

        this.connection.Close();
    }

    /// <summary>
    /// Gets the session id.
    /// </summary>
    /// <param name="con">The connection object.</param>
    /// <returns>The current oracle session id.</returns>
    public int GetSessionId(OracleConnection con)
    {
        OracleCommand cmd = new OracleCommand();
        cmd.Connection = con;
        cmd.CommandText = "select SYS_CONTEXT('USERENV','SID') from dual";
        object sid = cmd.ExecuteScalar();
        return Convert.ToInt32(sid);
    }
}

The ClientId is reset only on the connection close and if you are closing then its bound to be reset.

Connection pooling helps the database server to timeout an idle session and use the connection to service an active session. The idle logical session remains open, and the physical connection is automatically reestablished when the next request comes from that session. So is the connection actually closed ?

So it would be good to set the Session identifier by DBMS_SESSION.SET_IDENTIFIER

Hope this helps

It seems very dangerous to me to keep a reference to a database connection in your session. The idea of the connection pool is that a request borrows a connection for the duration of the request. When the request completes, the connection goes back to the pool. The connection will then be reused for more requests from different users.

I suspect that all sorts of nasty things happen when you store a connection in your session. You probably use the connection while it's being concurrently used by another request. Or you might get a closed connection because the connectin pool has to decide to close it.

Furthmore, the LOGON trigger is probably only executed when the database connection is created for the first time but is not executed again when the connection is reused for a different request or a different user.

To fix your problem, grab a database connection at the beginning of every request and explicitly set the Client ID (and/or execute the code that's run by the LOGON trigger). Then use this connection for the duration of the request. But don't store it anywhere after the request has finished.

That way, your connection is always properly initialized with the current user's context. And you adhere to the rules of the connection pool.

When connection pooling is enabled, which is good and of course the way to go in an ASP.NET scenario (and in most scenarios in fact), you should not store any db connection. You must open and close connections when you need it.

Here is a link about SQL Server, but it's the same with Oracle that explains it: SqlConnection Class

So the code you need to use when calling Oracle should be something like this, anywhere in your app, whenyou need it:

Using connection As New OracleConnection(connectionString)
    connection.Open()
    ' Do work here; connection closed on following line.
End Using

The thing is: you cannot have connection pooling enabled with specific user information in the connection string. So I suggest you implement your auditing code without using the connection string.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!